Field, Foreign Key, That Can Reference Multiples Tables - php

I am developing a social network for an intranet, and I came across a problem [?]. I have the entities User and Business as main entities of the network.
Note: A Business does not have, necessarily, a relationship with a User.
Following this idea, I have a group table, and a group can be created either by a user or by a business, there comes a question, how can I make the author field in this table?
I did the following, I created a table type, with the following data:
id | name
1 user
2 business
And my table groups like this:
id
name
description
tid (FK -> type.id)
author (INT)
Thus, if a group has a tid equals to 1, means that the author is referring to a User, if it have tid equals to 2, it is referring to a Business.
What do you think about this implementation? It is correct?
What can I do to improve it?
I'm using PHP 5.3.6 (Zend Framework and Doctrine2) + MySQL 5.1.

Per request:
The terminology for this is "polymorphic". Bill Karwin had a good answer that I can't find at the moment about it. From a database design perspective, I've been told the logical model term for this is an "arc" relationship. Either way, I see no issues with what you posted, other than supporting multiple authors.

The bad thing about this is that you cannot use the foreign key constraints to check and verify your data if you do this.
I would recommend using 2 tables instead. one to store the relationship between user and group, and one to store the relationship between business and group.
This will allow you to use all the fk benefits like cascading deleted when the group or business or user is deleted.

Related

Use one-to-one MySQL Relation or not?

I have user table, and I need to expand it with author and partner data. Should I put additional columns in same table or create 2 more tables (user_author and user_partner) with one-to-one relationship ?
Tables and columns are simplified for example.
user
id
name
email
password
avatar
is_active
user_author
user_id => user.id (PK, UNQ)
description
amount_per_text
max_text
is_active
user_partner
user_id => user.id (PK, UNQ)
name
description
image_logo
is_active
User cannot be both author and partner. And then I can have classes like User.php for normal users, UserPartner.php and UserAuthor.php which extends User.php class.
Does it make sense or should I just put those columns in user table ?
Both approaches are valid and frequently used.
The normalization theory of a relational schema would not allow to put all the data in a single table for reasons of data consistency. This would favor a multi-table approach.
In the single-table approach you'll end up with a lot of empty (null) fields in every record in the table.
When using multiple tables, however, you may have to perform one or two joins just to find out if a record is a partner or an author. Hence, from a performance viewpoint, the single-table solution is preferrable.
In both cases, you could include an extra field, e.g. "recordType", in user to quickly and easily discriminate between the different types of records. This will give the best possible runtime performance.

Backend app in OO PHP: Structuring classes/tables efficiently

I'm currently working on an app backend (business directory). Main "actor" is an "Entry", which will have:
- main category
- subcategory
- tags (instead of unlimited sub-levels of division)
I'm pretty new to OOP but I still want to use it here. The database is MySql and I'll be using PDO.
In an attempt to figure out what database table structure should I use in order to support the above classification of entries, I was thinking about a solution that Wordpress uses - establish relationship between an entry and cats/subcats/tags through several tables (terms, taxonomies, relationships). What keeps me from this solution at the moment is the fact that each relationship of any kind is represented by a row in the relationships table. Given 50,000 entries I would have, attaching to a particular entry: main cat, subcat and up to 15 tags might slow down the app (or I am wrong)?
I then learned a bit about Table Data Gateway which seemed an excellent solution because I liked the idea of having one table per a class but then I read there is virtually no way of successful combating the impedence missmatch between the OOP and relational-mapping.
Are there any other approaches that you may see fit for this situation? I think I will be going with:
tblentry
tblcategory
tblsubcategory
tbltag
structure. Relationships would be based on the parent IDs but I+'m wondering is that enough? Can I be using foreign key and cascade delete options here (that is something I am not too familiar with and it seems to me as a more intuitive way of having relationships between the elements in tables)?
having a table where you store the relationship between your table is a good idea, and through indexes and careful thinking you can achieve very fast results.
since each entry must represent a different kind of link between two entities (subcategory to main entry, tag to subcategory) you need at least (and at the very most) three fields:
id1 (or the unique id of the first entity)
linkid (linking to a fourth table where each link is described)
id2 (or the unique id of the second entity)
those three fields can and should be indexed.
now the fourth table to achieve this kind of many-to-many relationship will describe the nature of the link. since many different type of relationship will exist in the table, you can't keep what the type is (child of, tag of, parent of) in the same table.
that fourth table (reference) could look like this:
id nature table1 table2
1 parent of entry tags
2 tag of tags entry
the table 1 field tells you which table the first id refers to, likewise with table2
the id is the number between the two fields in your relationship table. only the id field should be indexed. the nature field is more for the human reader then for joining tables or organizing data

How to model database where different users/roles are in a project table, while all of them have to belong to user table?

I am trying to model a database for my current project and I came across a new problem. I have a Project which is supervised by Supervisor, Coordinator and Company. So Project table has Supervisor.id as foreign key and so on. There is also Student table which contains Project.is as a foreign key (because many users can do a project). This is how it is right now. What I would like to do is to have a User table containing a column named type which allows me to see what the role of that particular user is (also student). Even though the table will contain many NULL entries, I will have far less redundant code.
However, the main reason I want to have one User table is that I am using CakePHP and it is not easy to have different models log in. Is this possible in a nice way?
Thanks
EDIT: Maybe I should say that every one of these roles will have different permissions.
I see three tables: USER, GROUP, and ROLE.
Users would be assigned to groups, and groups given roles. I think you need three, not one.
And cardinality matters: I can see where a USER could be assigned to many GROUPS; a GROUP could have many USERS; a ROLE could be assigned to several GROUPS; and a GROUP could have many ROLES. There are many to many JOIN tables as well:
USER <-> USER_GROUP <-> GROUP <-> GROUP_ROLE <-> ROLE
This is normalized - nothing is repeated this way. USER, GROUP, and ROLE have primary keys. The JOIN table primary key is a composite of the two IDs in each row.
It depend on how you will use your associations.
Why not
For example: if you use relation to output data later and you sure, that you database scheme will not changed, than ... why not? your main targets: quality of code and speed of development, so, not matter how much columns with null you will have.
But
if you not sure in your requirements or plan to extend database scheme you can use two columns
supervisor_model
supervisor_id
which will store apropriate values: Company, 77 (I mean that 77 it's id of come Company )
Another approach
You can UUID for you supervisor_id so, it will be unique among several tables and you have not many NULL and extra columns.

How to keep data separate for businesses or groups of customers?

I've done quit a bit of programming with php/mysql on small scale personal projects. However I'm working on my first commercial app that is going to allow customers or businesses to log in and perform CRUD operations. I feel like a total noob asking this question but I have never had to do this before and cannot find any relevant information on the net.
Basically, I've created this app and have a role based system set up on my data base. The problem that I'm running into is how to separate and fetch data for the relevant businesses or groups.
I can't, for example, set my queries up like this: get all records from example table where user id = user id, because that will only return data for that user and not all of the other users that are related to that business. I need a way to get all records that where created by users of a particular business.
I'm thinking that maybe the business should have an id and I should form my queries like this: get all records from example where business id = business id. But I'm not even sure if that's a good approach.
Is there a best practice or a convention for this sort data storing/fetching and grouping?
Note:Security is a huge issue here because I'm storing legal data.
Also, I'm using the latest version of laravel 4 if that's any relevance.
I would like to hear peoples thoughts on this that have encountered this sort problem before and how they designed there database and queries to only get and store data related to that particular business.
Edit: I like to read and learn but cannot find any useful information on this topic - maybe I'm not using the correct search terms. So If you know of any good links pertaining to this topic, please post them too.
If I understand correctly, a business is defined within your system as a "group of users", and your whole system references data belonging to users as opposed to data belonging to a business. You are looking to reference data that belongs to all users who belong to a particular business. In this case, the best and most extensible way to do this would be to create two more tables to contain businesses and business-user relations.
For example, consider you have the following tables:
business => Defines a business entity
id (primary)
name
Entry: id=4, name=CompanyCorp
user => Defines each user in the system
id (primary)
name
Entry: id=1, name=Geoff
Entry: id=2, name=Jane
business_user => Links a user to a particular business
user_id (primary)
business_id (primary)
Entry: user_id=1, business_id=4
Entry: user_id=2, business_id=4
Basically, the business_user table defines relationships. For example, Geoff is related to CompanyCorp, so a row exists in the table that matches their id's together. This is called a relational database model, and is an important concept to understand in the world of database development. You can even allow a user to belong to multiple different companies.
To find all the names of users and their company's name, where their company's id = 4...
SELECT `user`.`name` as `username`, `business`.`name` as `businessname` FROM `business_user` LEFT JOIN `user` ON (`user`.`id` = `business_user`.`user_id`) LEFT JOIN `business` ON (`business`.`id` = `business_user`.`business_id`) WHERE `business_user`.`business_id` = 4;
Results would be:
username businessname
-> Geoff CompanyCorp
-> Jane CompanyCorp
I hope this helps!
===============================================================
Addendum regarding "cases" per your response in the comments.
You could create a new table for cases and then reference both business and user ids on separate columns in there, as the case would belong to both a user and a business, if that's all the functionality that you need.
Suppose though, exploring the idea of relational databases further, that you wanted multiple users to be assigned to a case, but you wanted one user to be elected as the "group leader", you could approach the problem as follows:
Create a table "case" to store the cases
Create a table "user_case" to store case-user relationships, just like in the business_user table.
Define the user_case table as follows:
user_case => Defines a user -> case relationship
user_id (primary)
case_id (primary)
role
Entry: user_id=1, case_id=1, role="leader"
Entry: user_id=2, case_id=1, role="subordinate"
You could even go further and define a table with definitions on what roles users can assume. Then, you might even change the user_case table to use a role_id instead which joins data from yet another role table.
It may sound like an ever-deepening schema of very small tables, but note that we've added an extra column to the user_case relational table. The bigger your application grows, the more your tables will grow laterally with more columns. Trust me, you do eventually stop adding new tables just for the sake of defining relations.
To give a brief example of how flexible this can be, with a role table, you could figure out all the roles that a given user (where user_id = 6) has by using a relatively short query like:
SELECT `role`.`name` FROM `role` RIGHT JOIN `user_case` ON (`user_case`.`role_id` = `role`.`id`) WHERE `user_case`.`user_id` = 6;
If you need more examples, please feel free to keep commenting.

Advice on database design for portfolio website

So I'm a visual designer type guy who has learned a respectable amount of PHP and a little SQL.
I am putting together a personal multimedia portfolio site. I'm using CI and loving it. The problem is I don't know squat about DB design and I keep rewriting (and breaking) my tables. Here is what I need.
I have a table to store the projects:
I want to do fulltext searcheson titles and descriptions so I think this needs to be MyISAM
PROJECTS
id
name (admin-only human readable)
title (headline for visitors to read)
description
date (the date the project was finished)
posted (timestamp when the project was posted)
Then I need tags:
I think I've figured this out. from researching.
TAGS
tag_id
tag_name
PROJECT_TAGS
project_id (foreign key PROJECTS TABLE)
tag_id (foreign key TAGS TABLE)
Here is the problem I have FOUR media types; Photo Albums, Flash Apps, Print Pieces, and Website Designs. no project can be of two types because (with one exception) they all require different logic to be displayed in the view. I am not sure whether to put the media type in the project table and join directly to the types table or use an intermediate table to define the relationships like the tags. I also thinking about parent-types/sub-types i.e.; Blogs, Projects - Flash, Projects - Web. I would really appreciate some direction.
Also maybe some help on how to efficiently query for the projects with the given solution.
The first think to address is your database engine, MyISAM. The database engine is how MySQL stores the data. For more information regarding MyISAM you can view: http://dev.mysql.com/doc/refman/5.0/en/myisam-storage-engine.html. If you want to have referential integrity (which is recommended), you want your database engine to be InnoDB (http://dev.mysql.com/doc/refman/5.0/en/innodb-storage-engine.html). InnoDB allows you to create foreign keys and enforce that foreign key relationship (I found out the hard way the MyISAM does not). MyISAM is the default engine for MySQL databases. If you are using phpMyAdmin (which is a highly recommended tool for MySQL and PHP development), you can easily change the engine type of the database (See: http://www.electrictoolbox.com/mysql-change-table-storage-engine/).
With that said, searches or queries can be done in both MyISAM and InnoDB database engines. You can also index the columns to make search queries (SELECT statements) faster, but the trade off will be that INSERT statements will take longer. If you database is not huge (i.e. millions of records), you shouldn't see a noticeable difference though.
In terms of your design, there are several things to address. The first thing to understand is an entity relationship diagram or an ERD. This is a diagram of your tables and their corresponding relationships.
There are several types of relationships that can exist: a one-to-one relationship, a one-to-many relationship, a many-to-many relationship, and a hierarchical or recursive relationship . A many-to-many relationship is the most complicated and cannot be produced directly within the database and must be resolved with an intermittent table (I will explain further with an example).
A one-to-one relationship is straightforward. An example of this is if you have an employee table with a list of all employees and a salary table with a list of all salaries. One employee can only have one salary and one salary can only belong to one employee.
With that being said, another element to add to the mix is cardinality. Cardinality refers to whether or not the relationship may exist or must exist. In the previous example of an employee, there has to be a relationship between the salary and the employee (or else the employee may not be paid). This the relationship is read as, an employee must have one and only one salary and a salary may or may not have one and only one employee (as a salary can exist without belonging to an employee).
The phrases "one and only one" refers to it being a one-to-one relationship. The phrases "must" and "may or may not" referring to a relationship requiring to exist or not being required. This translates into the design as my foreign key of salary id in the employee table cannot be null and in the salary table there is no foreign key referencing the employee.
EMPLOYEE
id PRIMARY KEY
name VARCHAR(100)
salary_id NOT NULL UNIQUE
SALARY
id PRIMARY KEY
amount INTEGER NOT NULL
The one-to-many relationship is defined as the potential of having more than one. For example, relating to your portfolio, a client may have one or more projects. Thus the foreign key field in the projects table client_id cannot be unique as it may be repeated.
The many-to-many relationship is defined where more than one can both ways. For example, as you have correctly shown, projects may have one or more tags and tags may assigned to one or more projects. Thus, you need the PROJECT_TAGS table to resolve that many-to-many.
In regards to addressing your question directly, you will want to create a separate media type table and if any potential exists whatsoever where a project is can be associated to multiple types, you would want to have an intermittent table and could add a field to the project_media_type table called primary_type which would allow you to distinguish the project type as primarily that media type although it could fall under other categories if you were to filter by category.
This brings me to recursive relationships. Because you have the potential to have a recursive relationship or media_types you will want to add a field called parent_id. You would add a foreign key index to parent_id referencing the id of the media_type table. It must allow nulls as all of your top level parent media_types will have a null value for parent_id. Thus to select all parent media_types you could use:
SELECT * FROM media_type WHERE parent_id IS NULL
Then, to get the children you loop through each of the parents and could use the following query:
SELECT * FROM media_type WHERE parent_id = {$media_type_row->id}
This would need to be in a recursive function so you loop until there are no more children. An example of this using PHP related to hierarchical categories can be viewed at recursive function category database.
I hope this helps and know it's a lot but essentially, I tried to highlight a whole semester of database design and modeling. If you need any more information, I can attach an example ERD as well.
Another posibble idea is to add columns to projects table that would satisfy all media types needs and then while editting data you will use only certain columns needed for given media type.
That would be more database efficient (less joins).
If your media types are not very different in columns you need I would choose that aproach.
If they differ a lot, I would choose #cosmicsafari recommendation.
Why don't you take whats common to all and put that in a table & have the specific stuff in tables themelves, that way you can search through all the titles & descriptions in one.
Basic Table
- ID int
- Name varchar()
- Title varchar()
etc
Blogs
-ID int (just an auto_increment key)
-basicID int (this matches the id of the item in the basic table)
etc
Have one for each media type. That way you can do a search on all the descriptions & titles at the one time and load the appropriate data when the person clicked through the link from a search page. (I assume thats the sort of functionality you mean when you say you want to be able to let people search.)

Categories