How to define many-to-many relationship in CakePHP - cakephp

I have an app in which Users belong to many Categories. So I have a Users table, Categories and Users2Categories table. The Users2Categories table consists of a user_id and category_id. So I guess the question is: do I create a model for Users2Categories? Ultimately, I would like to be able to "find" User objects and have their respective categories attached.
Also, can I define this relationship via the baking console?

Read about HABTM in the cookbook. Rename 'Users2Categories' table to 'categories_users'.
You can bake the models from the console but you must have the correct tables first (see above).

HABTM is definitely the way to go.
Cake will handle the join table for you, provided you adhere to the Cake conventions.
Read the section in the Book linked to by bancer, then read it again. Then read this: http://mrphp.com.au/code/working-habtm-form-data-cakephp which will help you with realworld implementation.

So, you asked two questions and got some good information, but the answers are pretty straightforward:
do I create a model for Users2Categories?
You can, but I wouldn't. Cake will create a model for the join at runtime. Since this model/table exists solely to facilitate the join (i.e. it has no properties or methods of its own), just let Cake do that work for you. As stated by #bancer, though, you will need to name the table according to Cake's convention.
Also, can I define this relationship via the baking console?
No. You can create the model skeleton, but that won't include the definition of any associations. AFAIK, there's no way to do that. Bake the skeleton, flesh it out with associations, etc.
I could not have been more wrong. See comments. Thanks for the education, #bancer and #beporter.

Related

How to model a database structure with repeating fields in every table

I'm in the process of structuring a databasemodel for my new project. For all the entities in my model (which is a cms, and the entities as such f.ex: page, content, menu, template and a bunch of others) they all have in common the same attributes on dates and names.
More specifically each entity contains the following for the dates: IsCreated, IsValidFrom, IsPublished, IsDeleted, IsEdited and IsExpired, and for names: CreatedByNameId, ValidFromByNameId, PublishedByNameId and so on...
I'm going to use EF5 for mapping to objects.
The question is as simple: What is the best way to structure this: Having all the fields in every table (which I am not obliged to...) or to have two separate tables which the other can relate to...?
Thanks in advance /Finn.
First of all - give this a read - http://www.agiledata.org/essays/mappingObjects.html
You really need to think about your queries/access paths. There are many tradeoffs between different implementations.
In reply to your example though,
Given the following setup:
COMMON
ValidFromByNameId
SPECIFIC1
FieldA
SPECIFIC2
FieldB
Querying by the COMMON attributes is easy but you'll have to work some magic when pulling up the subclasses (unless EF5 does it for you)
If the primary questions you're asking are about specific1 and specific2 then perhaps this isn't the right model. having the COMMON table doesn't really buy you much necessary as it will introduce a join to load any Specific1 object. In this case, i'd probably just have duplicate columns.
This answer is intentionally partial as a full answer is better handled by the numerous articles and blogs already out there. Search for "mapping object hierarchies to databases"

Cakephp workaround for model inheritance relationship

From my understanding, cakephp doesn't support database inheritance relationship. However, I want to create a database with different type of Users.
In this case, there are three types of Users: Seller, Customer, and Administrator. Every users should have basic User information such as password, username, etc.
However, each types of users will have its own unique set of datas. For example, seller may have inventory_id while customer may have something like delivery_address, etc.
I have been thinking of creating a workaround to this problem without destroying cakephp convention. I was going to create three additional foreign keys, admin_id, seller_id and customer_id, inside User table, which links to other table. However, knowing that this is an IS-A relationship not HAS-A, I would have to make sure that two of the ids are NULL value. Therefore, this workaround seems ugly to me..
Is there any other simpler, better approach?
For this type of database structure I would probably look at adopting an Entity-Attribute-Value model. This would mean your customer may have a delivery_address and your user may have an inventory_id but as far as your relationship in Cake is concerned your both your user and customer would just have an attribute_id ... you can then create another table that stores what type of attributes are available.
It it's simplest form, your user and customer would be attached to an *attribute_lookup* or *attribute_link* table by a hasMany (probably) relationship. That attribute_lookup/link table would be connected by a belongsTo/hasOne relationship to the actual Attribute Type and Attribute Value models.
Providing that you normalise your tables correctly, you can stick well within Cake relationship conventions.
You can read more about EAV here.
I have been thinking about this problem for some time now, and I have eventually got around to build a solution for it. What I came up with is a new ORM that can be used on top of CakePHP.
It sort of works as CakePHP 3.0 with entities that represent an id/model, but it is much more advanced and supports multi table inheritance and single table inheritance.
Check it out: https://github.com/erobwen/Cream

How do variable Model names work in CakePHP tables?

Looking at the tables (aros, acos) generated by the ACL component and for example the Favorites plugin by CakeDC I see the favorites table with the fields Favorite.user_id, Favorite.model and Favorite.foreign_key.
The last two combined are replacing the good old Favorite.post_id (presuming model has the value 'Post'). It is in a way a HABTM pivot table with a dynamic modelname on one side.
I can see the general and useful idea here but would like to know more about the application of it.
My question(s):
Does this pattern have a name?
How does this work code-wise? I can see the abstract principle, but what kind of model-code is needed to make this work? Does it involve a patchwork of queries, or does this allow for a smooth one-query implementention? E.g.: I'd like to fetch all marked-as-favorite Posts in the system and their related Users in one go.
And does this work both ways? (querying from both the Post model as well as the User model)
I'd like to work towards an abstraction where I put a behavior in place to take care of this pattern.
I did look into the CakeDC code but could not figure out the principle. It's a little too cryptic for my current knowledge. Hence my question here.
kind regards,
Bart
Does this pattern have a name?
http://en.wikipedia.org/wiki/Junction_table aka Join Table.
How does this work code-wise? I can see the abstract principle, but
what kind of model-code is needed to make this work? Does it involve a
patchwork of queries, or does this allow for a smooth one-query
implementention? E.g.: I'd like to fetch all marked-as-favorite Posts
in the system and their related Users in one go.
It is just a regular join table, that's all. You can simply rely on what CakePHP is building up when using the HABTM assocs or refine your query by using joins. See http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables.
The model field is not needed in that "pattern" but allows you to have just one join table that can be used for many different tables/models. For example instead of having tags and users and posts associated by tags_posts and tags_users we simply use the same table and filter by the model field.
And does this work both ways? (querying from both the Post model as
well as the User model)
Yes if you set the HABTM association up in both models.
Thanks for using our plugins. ;)

CakePHP baking self-joined models

I am trying to setup a self join and having hell.
For example, a User has a ContactList, which is just other Users. So ContactList is a join table connecting User to itself.
User
id | name
ContactList
id | user_id | friend_id
After baking however, im not getting the result i expect. I've googled solutions but they dont work for me. How is this kind of situation handled? Do i need to customize the model?
The solution is to set up your associations manually, per the CakePHP book [Associations].
How can CakePHP know what you're referring to with "friend_id" if there's no "friends" table? Hint: it can't.
There are plenty of great examples in the book on the page about Associations (the link above). Read through it and you'll most definitely have a better understanding.
It's not really considering "customizing the model" by doing things that aren't baked for you. Baking is just a quick way to get the bare-bones up and rolling, but it can't be expected to do ALL the work.
bake is able to generate a self referencing relation (only) if you specified a field named parent_id in your database

Implementing tag clouds with CakePHP

I did a little research on tag clouds, and I ended up choosing a schema similar to the Wordpress one seen in this page: http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html
Currently, the tables that I have created is: Posts, PostsTagMaps, PostsTags
1) Would I need to create a table for PostsTagMaps even if I don't plan on using a controller?
2) A Post hasMany PostTagMaps. I'm not sure where should I be defining this relationship. I think it should be the Post model, but then I would have to join the PostsTags table to PostTagsMaps then join it to Posts, so I wanted to ask for some advice.
The easy solution is to follow Cake conventions (which will look very similar to the solution you linked to). You'll have three tables:
posts, tags, posts_tags
Then your Post model HABTM Tag model. The join table will automatically be used by Cake to save and retrieve the information. Check the book for more information on setting up your schema.
Cake is flexible enough where you can do it however you want, but if it's a basic sort of posts-tags relationship, the convention method is the way to go.
If you want to use a custom model/table like PostsTagMaps, then do this by using the 'with' key in your HABTM relationship definition. The 'with' key tells Cake to use a specific model (and therefore a specific table) instead of an automatically generated version. In this case, your tag model sounds like it's PostsTags and your HABTM table is PostsTagMaps, so the 'with' key on Post HABTM PostsTag would be PostsTagMap.

Resources