Complex CakePHP queries - cakephp

I need a data-filter based on a child model HABTM relation condition.
My table structure is as following:
Project hasMany TaskGroup hasMany Task hasAndBelongsToMany User.
I need my find function to get only the Projects with specific TaskGroups that contain Tasks assigned to some User.id. In other words, I need my Tasks filtered by User.id, and structured as Project -> TaskGroup -> Task. Is there a way Cake model bindings handle this, or do I need to write the joins manually?

You'll need to use Joins - see link for how to build joins in CakePHP:
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables

Related

Plan and create database before baking any files?

I'm really new to cakephp (3). I have a general question about baking models, views and controllers.
Do I have to completely plan and create the database scheme before baking any m., v. or c?
I'm afraid of overwriting my codes, when I extend my database-scheme. I'm thinking of a situation like this:
I have two tables "Articles" and "Users". I baked mvc-s, having a small but complete website. I tweaked the Users-Model/Entity for some validator-reasons (e.g.).
Now, two weeks later, I want to add a "Group" table, where one user can belong to many groups.
Normally, I could rebake the Users-mvc-files. But that would overwrite my whole website.
Do I make a mistake? Do I have to manually modify the mvc-files when extending tables?
What is the best practice for extending a cakephp-website?
Many thanks in advance.
You could just bake the MVC for the new table, Groups (should be plural), and then update the associations, if any, in other tables. For example, if Users belongs to Groups, after baking the Groups table, you could add:
// in /src/Model/Table/UsersTable.php
$this->belongsTo('Groups', [
'foreignKey' => 'group_id'
]);
Of course, this assumes you've added the 'group_id' field to the Users table in your database.
This is a fine solution if your table is small and your data model remains fairly static. But if you are working with many tables and you are still regularly making changes to the model, I would suggest doing what I did after blowing away all my controller changes a couple of times.
CakePHP 3 makes very cool use of Elements in it's Controller templates. You can copy the cakephp vendor templates into your src directory, and then provide your additional controller methods (like login()/logout() in UsersController) as elements. Then test for the model and include the appropriate elements for that model.
This way you can bake away and not worry about losing all your changes.
Yes, generally you have to plan for database scheme before baking your MVC.
You should manually do the changes if any alter/changes become in the table otherwise the bake will override all the codes you did.
All the very best

CakePHP - How to save single hasMany through record with many belongsTo records per hasMany at once?

My models are essentially
owner hasOne album
asset hasMany album
album belonsTo owner
album belongsTo asset
A record in 'album' associates an asset to an owner, a 'link', containing extra information such as position, just as the cakephp example does here: hasMany through (The Join Model). Two problems - the docs demo saving via the hasMany/relationship controller, not either end, and in my case, the first model has one record, and the latter has many (in a single save).
When isolated, I can upload multiple assets in one form. The controller then calls saveManyIndividually(), a method inside the asset model, which uploads each asset with a corresponding DB record with a loop.
I'd like to do this when creating a new owner, so the owner form allows multiple assets to be uploaded (with corresponding records saved at once). Then an album (link) record needs to be created per asset record, with the foreign keys being the one, single owner_id through all, and a different asset_id in each.
I can't see a sure way of saveAssociated in the Owner controller doing this. Maybe I could use the asset->saveManyIndividually method in the beforeSave?
I can further clarify is this is unclear.
I think the best way to do this is to separate the operations in the controller:
Create the owner
Upload the assets and save records for them
save associations between the Owner ID and the asset record IDs
I haven't had time to do this yet, but if there's a better way to do so I'll edit.

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.

cakephp - a different has many through relationship

I was wondering if this is possible to do with a has many through
contents orgs folders
id id id
name name title
link
join table - folder_elements
id
element_id
order
contents has many folders through folder_elements
orgs has many folders through folder_elements
So my question is, is it possible to use element_id to store the content.id or the org.id ?
Alex
What you're describing is a sort of HABTM (HasAndBelongsToMany) association. You could define the inter-model associations as you suggest, but there's a pretty significant design flaw: how would you account for a situation where the same ID is used for an orgs record and a contents record, and wish to associate them with the same folder record? It would be impossible to differentiate between the two in your joining table.
There are a number of ways to work around this, but they require more program logic or a more disorganised database schema that presents challenges in maintainability.
The more elegant, robust solution is to rationalise your database structure. If there's no pressing need to have One Join Table to Rule Them All, you could design your model associations like this:
Content hasMany ContentsFolder belongsTo Folder
Folder hasMany ContentsFolder belongsTo Content
Org hasMany OrgsFolder belongsTo Folder
Folder hasMany OrgsFolder belongsTo Org
This is the internal structure of a HABTM association defined explicitly so you can define fields in the joining table. Your contents and folders tables would remain the same, but your two joining tables would look like:
contents_folders
-> id
-> content_id
-> order
orgs_folders
-> id
-> org_id
-> order
Unfortunately, yes, this would require defining five models instead of three, but such are the limitations of CakePHP's object-relational modelling.

Recursive Pagination in CakePHP Not Working

I apologize if this question has been asked and answered elsewhere but I have looked and have not been able to find it.
I have three models:
Manager HABTM Tenant
I also have a ManagersTenant model to tie the two together.
I'm trying to use pagination to recursively display fields from Manager and Tenant in the ManagersTenant controller. Here is my code:
$this->ManagersTenant->recursive = 2;
$this->set('managersTenants', $this->paginate('ManagersTenant',array(),array('recursive'=>2)));
This displays only the fields in ManagersTenant (id, tenant_id, manager_id) but does not retrieve data from the associated Manager and Tenant models.
I am also doing a debug($this->ManagersTenant->find('all')); which performs the recursion perfectly and displays the right arrays.
What am I doing wrong? Do I need to do anything special with my model(s)?
Any help is much appreciated.
//edit:
What I'm trying to do is display all matches where Tenant_id or Manager_id matches the logged-in user's id. For example, if a logged-in Manager performs the index function on the Tenant model, I would like for all Tenants to be displayed for Tenant_id where Manager_id (in the ManagersTenant model) == $this->Auth->User('id'). I was under the impression that in order to do this, I had to utilize a HABTM table. But if it is possible for me to do Manager HABTM Tenant without a joining table, I am all for trying it.
You probably don't need to define the ManagersTenant model. You should define HABTM in the Manager and in the Tenant model, and use those models for your query.
If you really need a ManagersTenant model you should use the join model relationship:
Manager hasMany ManagersTenant
Tenant hasMany ManagersTenant
ManagersTenant belongsTo Manager and Tenant.

Resources