There are numerous 'getting started' tutorials out there on how to implement zfc-user and zfc-rbac into Zend Framework 2. The github pages for zfc-user and zfc-rbac (https://github.com/ZF-Commons) are clear and the implementation is indeed pretty easy (as stated on many of the tutorials). I also found the SQL schemes which are needed for both zfc-user and zfc-rbac (/vendor/zf-commons/zfc-[user/rbac]/data/).
The creation of a user into the database is easy, since zfc-user already sets this up for you (http://example.com/user). Everything fine so far. Now I want to populate the roles, but it's not clear to me on how to populate the rbac tables correctly. The lack on information about this surprises me, since the zfc-rbac component is a popular module for the Zend Framework.
I understand the principal of Role Based Access Control and the population of the tables for the permissions and the table linking the permissions and roles together are clear, it's the role table that's not clear to me. I understand that you can have a role which has a parent role, but it's not clear how to populate the table with a parent role since there is a foreign key constraint which states the 'parent_role_id' has to be a 'role_id'.
Below is the SQL for the role table (this is the SQL provided by zfc-rbac):
CREATE TABLE `rbac_role` (
`role_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`parent_role_id` int(11) unsigned NOT NULL,
`role_name` varchar(32) NULL,
PRIMARY KEY (`role_id`),
KEY `parent_role_id` (`parent_role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
ALTER TABLE `rbac_role`
ADD CONSTRAINT `rbac_role_ibfk_1` FOREIGN KEY (`parent_role_id`) REFERENCES `rbac_role` (`role_id`);
With the foreign key in place adding a parent role seems impossible?
INSERT INTO `rbac_role` (parent_role_id, role_name) VALUES (NULL, 'admin');
Basically my question is (and I feel very stupid for asking this) but how does an insert for a parent role look like? And if the insert statement I presented is in fact correct, do I always need to remove the foreign key before inserting a parent role?
Change your create table to the following:
CREATE TABLE `rbac_role` (
`role_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`parent_role_id` int(11) unsigned NULL,
`role_name` varchar(32) NULL,
PRIMARY KEY (`role_id`),
KEY `parent_role_id` (`parent_role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
Notice that parent_role_id is NULL instead of NOT NULL. If parent_role_id is NOT NULL then that means that it has to have a parent but since the foreign key reference is to the same table there is no way to insert a parent row!
fyi: This issue has been fixed. Version 0.2.0 of zfc-rbac will allow NULL value as parent_role_id
Related
Given the following database schema (MySQL), I'm worried about possibly introducing ambiguous naming in its PHP 5.5 model class given below (abstracted for simplicity).
CREATE TABLE `catalog_item` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`catalog_id` int(11) NOT NULL DEFAULT '0'
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `catalog_item_property` (
`catalog_item_id` int(11) NOT NULL DEFAULT '0',
`catalog_item_properties_id` int(11) NOT NULL DEFAULT '0'
PRIMARY KEY (`catalog_item_id`,`catalog_item_properties_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `catalog_item_properties` (
`id` int(11) NOT NULL AUTO_INCREMENT
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `catalog_item_properties_description` (
`catalog_item_properties_id` int(11) NOT NULL DEFAULT '0',
`language_id` int(11) NOT NULL DEFAULT '0'
PRIMARY KEY (`catalog_item_properties_id`,`language_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Some background on the schema:
catalog_item holds items from a catalog.
catalog_item_property holds all properties belonging to a catalog_item.
catalog_item_properties holds a list of all possible item properties.
catalog_item_properties_description holds a multi-language description for all catalog_item_properties.
I'm following a singular naming convention for all my tables.
The interface function names that I am unsure of:
public function getItemProperty($id)
{
// Get all catalog item properties that belong to this catalog item?
}
public function getItemProperties()
{
// Get list of all possible catalog item properties?
}
As you can see, on my current iteration, getItemProperty may return more than one property. But so does getItemProperties. Ideally, I would like the function naming to speak for themselves, and for there to be no ambiguity at all. I would also like there to be a strong relation between the function names and the schema table names, for the sake of consistency.
Some questions I would love to hear some informed opinions on:
Do I change either the table names, or the function names (or both?) to resolve this potential ambiguity? Or, might there be no ambiguity at all?
Is it ok to mix the singular and plural form on table names in this scenario?
I'm pretty new to database design. If I completely missed the best practice approach here, please do let me know. Thank you in advance for sharing your thoughts!
I find Yii2 documentation seriously lacking in documentation about i18n, particularly about using database instead of files for the translation messages.
I see documentation (EDIT: sorry, this was the link I meant) mentions the DbMessageSource class and somewhere else I found that the db tables should be named source_message and message but nowhere does it tell me the schema for those tables! And the yii message/extract command doesn't seem to auto-create the tables either.
How do I go about this?
Your documentation link is about a yii2 extension, you should read instead :
Internationalization - Message Translation
yii\i18n\DbMessageSource
If you don't want to use migration and need SQL instead, files for all databases are in migrations directory.
https://github.com/yiisoft/yii2/tree/master/framework/i18n/migrations
For example, the schema for MySQL is :
CREATE TABLE `source_message`
(
`id` integer NOT NULL AUTO_INCREMENT PRIMARY KEY,
`category` varchar(255),
`message` text
);
CREATE TABLE `message`
(
`id` integer NOT NULL,
`language` varchar(16) NOT NULL,
`translation` text
);
ALTER TABLE `message` ADD CONSTRAINT `pk_message_id_language` PRIMARY KEY (`id`, `language`);
ALTER TABLE `message` ADD CONSTRAINT `fk_message_source_message` FOREIGN KEY (`id`) REFERENCES `source_message` (`id`) ON UPDATE CASCADE ON DELETE RESTRICT;
The source_message table stores the messages to be translated, and the message table stores the translated messages. The name of these two tables can be customized by setting $sourceMessageTable and $messageTable, respectively.
Alright, I have been searching and finding very much about this subject,
but nothing satisfying.
I want to keep track of who has liked what, not just add a +1 to a table.
I have three tables: posts, comments and likes.
The table design looks like this for the moment
CREATE TABLE IF NOT EXISTS `likes` (
`like_id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`post_id_fk` INT(11),
`comment_id_fk` INT(11),
`uid_fk` int(11) NOT NULL,
`date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`ip` varchar(39) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0.0.0.0',
FOREIGN KEY (uid_fk) REFERENCES users(uid),
FOREIGN KEY (post_id_fk) REFERENCES post(post_id),
FOREIGN KEY (comment_id_fk) REFERENCES comments(comments_id),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;
And as you can see i have three different foreign keys, uid_fk for the user uid so i can know who has liked what. And now comes there problem, one foreign key to post_id and one for comments_id.
Mysql won't accept a foreign key if it doesn't exist. if i want to "like" a comment, it won't let be because of the foreign key of post_id_fk.
How to solve this DB mess?
And the AJAX like/delike problem:
I found this jQuery : Changing class of button with AJAX call when i was searching, and it looks simpel and very nice. And i have also follow this http://pluscss.com/tutorials/ajax-like-script-using-php-mysql-jquery tutorial. But I'm having problems combine them.
This is what I'm trying to do:
count the current amount of likes
check if the user have liked it before
give the user the option to like (or delike if previously liked)
with ajax and like.php
Could someone help me with this i would be very thankful!
It would be better to separate the tables.
Create a post_likes table and comments_likes table.
That way not only you're getting rid of your existing problem but the structure is more decoupled and more reusable.
I'm quite new to mysql. I want to make a database in mysql for a school. This database should store teachers' information and give some of these teachers the possibilities to create groups.
So I created a database that contains a table group and a table professeur. Group has many-to-many relationship with teachers and vice-versa which derives another table Group_professeur. Here is a simple structure of the tables:
Professeur:
CREATE TABLE IF NOT EXISTS `professeur` (
`id_professeur` int(11) NOT NULL AUTO_INCREMENT,
`nom_professeur` varchar(50) NOT NULL,
`prenom_professeur` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id_professeur`),
UNIQUE KEY `LOGIN` (`login`),
UNIQUE KEY `MDP` (`passwd`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=103 ;
Group
CREATE TABLE IF NOT EXISTS `groupe` (
`id_groupe` int(11) NOT NULL AUTO_INCREMENT,
`nom_groupe` varchar(255) NOT NULL,
`id_prof_responsable` int(11) NOT NULL,
PRIMARY KEY (`id_groupe`),
UNIQUE KEY `nom_groupe` (`nom_groupe`),
KEY `id_prof_responsable` (`id_prof_responsable`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
ALTER TABLE `groupe`
ADD CONSTRAINT `fk_professeur_to_groupe` FOREIGN KEY (`id_prof_responsable`) REFERENCES `professeur` (`id_professeur`) ON UPDATE CASCADE
Groupe_has_teachers:
CREATE TABLE IF NOT EXISTS `groupe_professeur` (
`id_groupe` int(11) NOT NULL,
`id_professeur` int(11) NOT NULL,
KEY `id_groupe` (`id_groupe`),
KEY `id_professeur` (`id_professeur`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `groupe_professeur`
ADD CONSTRAINT `groupe_professeur_ibfk_2` FOREIGN KEY (`id_professeur`) REFERENCES `professeur` (`id_professeur`) ON UPDATE CASCADE,
ADD CONSTRAINT `groupe_professeur_ibfk_1` FOREIGN KEY (`id_groupe`) REFERENCES `groupe` (`id_groupe`) ON UPDATE CASCADE;
Teachers can modify only the group(s) they created(i.e they can insert and delete members from their groups). Also, not all teachers have the right to create and modify groups.
After creating the tables, I was wondering who will give them the appropriate rights to do all these stuffs. I thought about creating an administrator. The admin can give the rights to certain teachers to create and modify their own groups and can also revoke these privileges.
I created a table which will store an administrator but who will give the admin the necessary rights to do these. Which brings me back to square one. And this table might have some relationships with other tables in the database thereby deriving some unnecessary tables.
Anyway I thought about changing the professors table to something general like staffs and adding the admin to the table. And then adding these staffs to the database. That means creating a new staff corresponds to adding the staff's information to the table staffs and then adding this staff as a user to the database. From there I can use SQL functions like GRANT and REVOKE to each user.
I'm not sure if this method is very efficient because these means if the school has 1000 professors then it has 1000 users in it's database.
Is there any efficient way to tackle this problem? Thanks.
Controlling application user access using the built-in MySQL notion of a user is unorthodox. For a basic application, I would recommend having another column in the group table for an owner_user_id that would refer to the professor table. Then in the application code, check for that id when the group is being altered.
Good luck!
You'll want to take a look at Role-based Access Control
Another explanation by Tony Marston
I have inherited a PHP project and the client is wanting to add some functionality to their CMS, basically the CMS allows them to create some news, all the news starts with the same content, and that is saved in one table, the actually news headline and articles are saved in another table, and the images for the news are saved in another, basically if the base row for the news is deleted I need all the related rows to be deleted, the database is not setup to work with foreign keys so I cannot use cascade deletion, so how can I delete the all the content I need to, when I only what the ID of the base news row is?
Any help would be very helpful I am sorry I cannot give you much more help, here is this the original SQL of tables scheme if that helps?
--
-- Table structure for table `mailers`
--
CREATE TABLE IF NOT EXISTS `mailers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`mailer_title` varchar(150) NOT NULL,
`mailer_header` varchar(60) NOT NULL,
`mailer_type` enum('single','multi') NOT NULL,
`introduction` varchar(80) NOT NULL,
`status` enum('live','dead','draft') NOT NULL,
`flag` enum('sent','unsent') NOT NULL,
`date_mailer_created` int(11) NOT NULL,
`date_mailer_updated` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=13 ;
-- --------------------------------------------------------
--
-- Table structure for table `mailer_content`
--
CREATE TABLE IF NOT EXISTS `mailer_content` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`headline` varchar(60) NOT NULL,
`content` text NOT NULL,
`mailer_id` int(11) NOT NULL,
`position` enum('left','right','centre') DEFAULT NULL,
`created_at` int(10) NOT NULL,
`updated_at` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=18 ;
-- --------------------------------------------------------
--
-- Table structure for table `mailer_images`
--
CREATE TABLE IF NOT EXISTS `mailer_images` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(150) NOT NULL,
`filename` varchar(150) NOT NULL,
`mailer_id` int(11) NOT NULL,
`content_id` int(11) DEFAULT NULL,
`date_created` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=15 ;
It is worth noting that the schema cannot be changed nor can I change to the DB to MYISAM so that I can use foreign keys.
Add foreign key to table mailer_content
FOREIGN KEY (mailer_id)
REFERENCES mailers(id)
ON DELETE CASCADE
Add foreign key to table mailer_images
FOREIGN KEY (content_id)
REFERENCES mailer_content(id)
ON DELETE CASCADE
http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html
It is worth noting that the schema cannot be changed nor can I change to the DB to MYISAM so that I can use foreign keys.
Why can't the schema be changed? You designed the app, didn't you? Even if you didn't, adding the proper keys is just a matter of adding the right indexes and then altering the right columns. #Michael Pakhantosv's answer has what looks to be the right bits of SQL.
Further, it's InnoDB that does foreign keys, not MyISAM. You're fine there already.
If you could change the schema, making the appropriate IDs actual, real Foreign Keys and using ON DELETE CASCADE would work. Or maybe triggers. But that's just asking for it.
Now, for some reason, ON DELETE CASCADE isn't liked very much around here. I disagree with other people's reasons for not liking it, but I don't disagree with their sentiment. Unless your application was designed to grok ON DELETE CASCADE, you're in for a world of trouble.
But, given your requirement...
basically if the base row for the news is deleted I need all the related rows to be deleted
... that's asking for ON DELETE CASCADE.
So, this might come as a shock, but if you can't modify the database, you'll just have to do your work in the code. I'd imagine that deleting a news article happens in only one place in your code, right? If not, it'd better. Fix that first. Then just make sure you delete all the proper rows in an appropriate order. And then document it!
If you can not change the schema then triggers are not an option.
InnoDB supports transactions, so deleting from two tables should not be an issue, what exactly is your problem?
P.S. It would be worth noting which version of the server are you using.