First, sorry for my language skills, I am not used to writing in English. ;)
I'm trying to develop my first cakePHP application.
What I'm trying to do:
Users are in groups and groups have
access to different locations.
Users can add reservations for this
locations.
So my main problem is to find the best way to get the permissions of the user:
The user should only see the locations on which he has access.
If a user tries to add a reservation for a location, I have to check his permission for this location.
etc.
I also have moderators and admins, but I think this is a similar problem.
So, how can I do this properly? The ACL doesn't seem to be the right way - in most tutorials it controls the access to actions, not to db-rows.
What my Database looks like:
I have a user table and use the AuthComponent to manage the authentication. This works fine.
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(64) NOT NULL,
`password` varchar(64) NOT NULL,
`enabled` tinyint(1) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
)
I have a groups table for usergroups.
CREATE TABLE IF NOT EXISTS `groups` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
)
CREATE TABLE IF NOT EXISTS `groups_users` (
`group_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
UNIQUE KEY `group_id` (`group_id`,`user_id`)
)
And I have my locations.
CREATE TABLE IF NOT EXISTS `locations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
`adress` text NOT NULL,
`description` text,
`created` datetime DEFAULT NULL,
`modified` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
)
The table contains the permissions, which group has access to which location.
CREATE TABLE IF NOT EXISTS `groups_locations` (
`group_id` int(11) NOT NULL,
`location_id` int(11) NOT NULL,
UNIQUE KEY `group_id` (`group_id`,`location_id`)
)
Of course the reservations table:
CREATE TABLE IF NOT EXISTS `reservations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`location_id` int(11) NOT NULL,
`start` date NOT NULL,
`end` date NOT NULL,
`user_id` int(11) NOT NULL,
`created` datetime DEFAULT NULL,
`modified` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
)
THX
Are you sure that you need the groups_users table? Wouldn't each user only be able to belong to one group?
You will be able to accomplish this much easier if you just bring the group id into the users table as a foreign key
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(64) NOT NULL,
`password` varchar(64) NOT NULL,
`enabled` tinyint(1) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
`group_id` int(11) NOT NULLL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
)
Then you can send to the view whether or not the user should be able to see certain information...
in your app_controller.php add the following
function beforeFilter(){
$this->set('users_role', $this->Auth->user('group_id'));
}
Now you will have a variable accessable by your view which will be $users_role... then you can perform the following in your view.
<?php if($users_role == 1 ): ?>
//show records available to admins
<?php elseif ($users_role == 2): ?>
//show records available to logged in users
<?php else : ?>
//show records for all users
<?php endif; ?>
Maybe I have a solution - I could use some feedback:
After the user logged in, I save the permissions in his Session-Variables:
function login() {
if($user = $this->Auth->user()) {
$this->User->unbindModel(array(
'hasMany' => array('Reservation'),
));
$user = $this->User->find('first', array('conditions' => array('id' => $user['User']['id']), 'recursive' => 2));
$this->Session->write('Auth.User.Group', $user['Group']);
}
I'm not sure how secure this solution is and permission changes only affects after logout, but it seems to work fine.
Related
I have the following 2 tables, and the default classes generated from
bin/cake bake all clients
bin/cake bake all clients_address
When I try and add an address, setting the "client_id" to 1, I get the following error.
Error: SQLSTATE[HY000]: General error: 1364 Field 'client_id' doesn't have a default value
If you are using SQL keywords as table column names, you can enable identifier quoting for your database connection in config/app.php.
SQL Query:
INSERT INTO clients_address (address_line_1, address_line_2, address_line_3, town, county, postcode, email, tel, contact_name, default_address) VALUES (:c0, :c1, :c2, :c3, :c4, :c5, :c6, :c7, :c8, :c9)
Is there some extra code needed to get the client_id to be submitted?
CREATE TABLE `clients` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `clients_address` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`address_line_1` varchar(30) NOT NULL,
`address_line_2` varchar(30) NOT NULL,
`address_line_3` varchar(30) NOT NULL,
`town` varchar(30) NOT NULL,
`county` varchar(30) NOT NULL,
`postcode` varchar(8) NOT NULL,
`email` varchar(50) NOT NULL,
`tel` varchar(13) NOT NULL,
`contact_name` varchar(40) NOT NULL,
`client_id` int(11) NOT NULL,
`default_address` BOOLEAN NOT NULL DEFAULT 0,
FOREIGN KEY (client_id) REFERENCES clients(id),
PRIMARY KEY (`id`)
);
INSERT INTO `clients` (`id`, `name`) VALUES (1, 'First Client');
In your clients_address Table schema client_id int(11) NOT NULL, set. But when you insert a Address then you don't set value against client_id and client_id can't be NULL
Probably solutions
Set client_id in Address insert query
In your table schema client_id allow NULL or set a default value
You need to be sure that "client_id" is sent. Check with your Debug Kit bar on History, select the POST request, and then go to Sql log.
There must be a query like this:
INSERT INTO clients_address (
client_id, address, modified
)
VALUES
(
61, 'my address', "123..."
)
If not maybe something is wrong with your Form.
Your query must be something like this:
INSERT INTO clients_address (address_line_1, ..., contact_name, CLIENT_ID, default_address)
VALUES (:c0, :c1, :c2, :c3, :c4, :c5, :c6, :c7, :c8, :c9)
If you are adding addresses standalone (addresses controller add method), you must stipulate "client_id" manually on Form, or from a hidden field based on a parameter, with Cake bake it will make a list of Clients on Add and Edit methods.
If you are adding the address from Client Form as an association, on CakePHP docs are some good examples https://book.cakephp.org/3.0/en/views/helpers/form.html#creating-inputs-for-associated-data
I am setting up a website with a script that creates several MySQL databases during installation, and from time to time I have to reinstall the script several times because of changes I've made. During the re-installation, the install script wipes all the groups and categories in those groups. I have to manually input the groups and categories again.
This is two instances of the code and both wipe out databases that I have created and populated.
DROP TABLE IF EXISTS `categories`;
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) unsigned NOT NULL auto_increment,
`category_name` varchar(255) character set utf8 NOT NULL,
`group_id` smallint(6) unsigned NOT NULL,
`description` text character set utf8 NOT NULL,
`page_title` varchar(255) character set utf8 NOT NULL,
`meta_keywords` text character set utf8 NOT NULL,
`meta_description` text character set utf8 NOT NULL,
`is_active` tinyint(4) NOT NULL default '1',
`created` int(11) NOT NULL,
`modified` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=13 ;
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) unsigned NOT NULL auto_increment,
`category_name` varchar(255) character set utf8 NOT NULL,
`group_id` smallint(6) unsigned NOT NULL,
`description` text character set utf8 NOT NULL,
`page_title` varchar(255) character set utf8 NOT NULL,
`meta_keywords` text character set utf8 NOT NULL,
`meta_description` text character set utf8 NOT NULL,
`is_active` tinyint(4) NOT NULL default '1',
`created` int(11) NOT NULL,
`modified` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=13 ;
Of course it nukes it; you call
DROP TABLE IF EXISTS `categories`;
That's what DROP TABLE does: destroy the table.
DROP TABLE IF EXISTS categories;
was in the original script and after I discovered the problem I removed that line of code and included only the second example above. It still wipes out the category database even with that line of code removed.
Confusing?!
Thanks,
i am using the following statement.
$users = $this->User->find('all');
But in the database there are only 174 rows. but the query is returning 200 rows.
When i out put the content i see that a lot of rows are repeated.
Any idea why this behavior in cakephp ?
Structure
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`first_name` varchar(255) NOT NULL,
`last_name` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`username` varchar(255) NOT NULL,
`password` varchar(40) NOT NULL,
`display_photo` varchar(255) DEFAULT NULL,
`subscription_plan_id` int(11) unsigned NOT NULL,
`company_id` int(11) NOT NULL,
`status` tinyint(2) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=177 ;
by trying to debug using this statment
echo $users = $this->User->find('count');
i get 200 itself.
Models: http://pastebin.com/p4bFPiUz
The query you are running does not nearly match the queries that CakePHP will actually execute. CakePHP will also perform all the required joins to get related data. So, this is not really a proper comparison that you are doing.
Some of your relations might return double results, like User -> CompanyA, but there could also be a User -> CompanyB relation, which would trigger 2 result rows for 1 single user.
To see the queries that Cake actually executes, use the getLog method on your datasource, like:
$ds = $this->User->getDataSource();
$log = $ds->getLog();
debug($log);
Or use something like DebugKit to get a panel with all the queries by default (when in debug mode).
I am working on a setup where I am unsure how to get correct associations setup.
Cakephp 1.3
I am thinking something like this, please correct me if I am wrong!
database:
CREATE TABLE IF NOT EXISTS `trips` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`user_id` bigint(20) NOT NULL,
`location_to` bigint(20) NOT NULL,
`location_from` bigint(20) NOT NULL,
`published` int(1) DEFAULT NULL,
`created` datetime DEFAULT NULL,
`modified` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ;
CREATE TABLE IF NOT EXISTS `locations` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `locations_from` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`trip_id` bigint(20) NOT NULL,
`location_id` bigint(20) NOT NULL
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `locations_to` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`trip_id` bigint(20) NOT NULL,
`location_id` bigint(20) NOT NULL
PRIMARY KEY (`id`)
);
But how to setup the models TRIP and LOCATION for correct HABTM ?
Trips belongsTo USER
Trips has a from location and to location => From New York, To Miami
Locations => New York, Miami +++
Use belongsTO og hasandbelongstomany? Working with several identifiers is a first for me.
Anyone that can give some assistance? Thanks!
-Tom
I recommend a hasAndBelongsToMany. Remember, a trip could have multiple locations, not just two.
I would re-construct your tables like this:
CREATE TABLE IF NOT EXISTS `trips` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`user_id` bigint(20) NOT NULL,
`published` int(1) DEFAULT NULL,
`created` datetime DEFAULT NULL,
`modified` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ;
CREATE TABLE IF NOT EXISTS `locations` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `locations_trips` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`location_id` bigint(20) NOT NULL
`trip_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`)
);
and let CakePHP bake this and take care of the rest (it will automatically pick up the HABTM relationship from the common table).
EDIT: Sorry, based on your comments, I think this would be better:
CREATE TABLE IF NOT EXISTS `trips` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`user_id` bigint(20) NOT NULL,
`locationfrom_id` bigint(20) NOT NULL,
`locationto_id` bigint(20) NOT NULL,
`published` int(1) DEFAULT NULL,
`created` datetime DEFAULT NULL,
`modified` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ;
CREATE TABLE IF NOT EXISTS `locations` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL
PRIMARY KEY (`id`)
);
and then use multiple relations to the same model as below:
http://book.cakephp.org/1.3/view/1046/Multiple-relations-to-the-same-model
For your example, locationfrom_id and locationto_id would belongsTo two classes that would have the same "className", which is Locations.
belongsTo is the correct way to represent it because you have only 2 locations by trip and those 2 locations have different meanings.
HABTM would have been correct if you had defined a trip this way :
During a trip, you go to many locations and you don't know how many.
If you are really planing on using more than two locations for a single trip you should create a new table which associates the trips with the locations and give them an order.
CREATE TABLE IF NOT EXISTS `location_trips` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`location_id` bigint(20) NOT NULL,
`trip_id` bigint(20) NOT NULL,
`number` bigint(20) NOT NULL
PRIMARY KEY (`id`)
);
The HABTM association would than be applied to the Trip model.
If you want to find trips while using the Location model as well, you have to define it there, too. ;)
Greetings
func0der
I have only two tables in my database with a one-to-many relationship between them (user hasMany messages) and am trying to get basic CRUD functionality going. Bake detects the associations correctly and specifies them correctly inside the model classes, but in controllers and views it looks like Cake doesn't know anything about those associations -- I don't even get a select tag for user_id when I go add a new message. Has anyone come across this problem before? What can I be doing wrong?
Table structure appears to be fine:
CREATE TABLE users (
id int(11) NOT NULL AUTO_INCREMENT,
username varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
email varchar(255) NOT NULL,
created datetime NOT NULL,
modified datetime NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `messages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`content` varchar(255) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
If you're using the console to bake your MVC files you could try that.
First bake the model files. Then bake the controller files using scaffold.
Then bake the view files.
Finally go back and bake the controller files without scaffold.
This should get you all basic CRUD functionality with all the associations you may have.
Hope that helps ...