Displaying a name of a non directly joined model in a pagination - cakephp

Press Story belongsTo Company
Company belongsTo Sector
Is there a way to display a list of the Press Stories, having the name of the company and the name of the sector?
The array returned by cake when paginating Press Stories contains Company and Press information but no additional information about the Sector.

use recursive => '2' in find condition.
See this link.
Ex: $this->Model->find('all', array('conditions' => array(....),
'recursive' => '2'));

Related

Issue in hasMany associated model data update/modify

I have two table,
categories hasMany products
id
name
active
products belongsTo categories
id
name
category_id
active
When I am editing the categories, in the same time I am also displaying the Products related to the category so that I can update/modify products related to the category.
Issue:- When I add more products for the category that works fine but when I remove some products from the category,the removed product does not get deleted from the database. So I want to know that This functionality is supported by CakePHP or not. If yes please help me to find where I am going wrong.
Here is the save code:-
$categoryProducts = $this->Categories->get(1, [
'contain' => 'Products'
]);
if($this->request->is['post', 'put']){
$entity = $this->Categories->patchEntity($categoryProducts, $this->request->data);
$this->Categories->save($entity);
}
When you set up your hasMany relationship, add 'saveStrategy' => 'replace'. See the hasMany section of the manual for details.

How do I add a HABTM record in CakePHP?

I am new to CakePHP and have a fairly basic question.
I have two tables : books and users. books and users have a habtm relationship. I have created the MVC for the above.
Now when a user logs into the system, I want the user to be able to reserve a book (ie an entry in books_users), by looking at the results of the 'index' action. What is the API to be used?
$this->Book->save() does not seem appropriate as we aren't creating a book. We only want an association between an existing book and the logged-in user.
I am trying to avoid, retrieving $this->Book, iterating manually through the sub-array User, creating a new sub-array and saving the whole thing back. I am sure there must be a simpler way.
Adapted from Chuck's answer, unsure why edit was pushed back.
In app/Model/Book.php
class Book extends AppModel {
/************************************************************************
* If you want your multiple assoc. to work you must set unique to *
* false, otherwise when you save an entry it will enforce unique *
* on book ID and subsequently your associations will delete previously *
* saved associations, acting more like "User HasMany Books". *
************************************************************************/
var $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'unique' => false
));
public function addUser($bid, $uid) {
$this->data['User']['id'] = $uid;
$this->data['Book']['id'] = $bid;
$this->save($this->data);
}
}
In app/Controller/BooksController.php (or UsersController)
$this->Book->addUser($bid, $uid);
Fat Models / Skinny Controllers. Allows duplicate entries (you need to constrain limits and check for duplicates, otherwise default behaviour makes HMBTM difficult). Does exactly what you want it to, you just need to supply book and user id.
CakePHP doesn't tend to encourage complex associations, and the reason this is because HMBTM is just a convenience and care should be taken when mixing it with other associations, as per the link provided below, self defined associations are more predictable than HMBTM in CakePHP
http://book.cakephp.org/2.0/en/models/saving-your-data.html#what-to-do-when-habtm-becomes-complicated
You simply need to save a record to Book or User that contains the ids of both and it will insert it into the HABTM table.
$this->data['User']['id'] = {USER_ID};
$this->data['Book']['id'] = {BOOK_ID};
$this->Book->save($this->data);
Look at the HABTM table and you will find the record.
did you bake your application? This (basic) functionality will be provided to you for you to adapt.
In short - take the id of the book and the id of the user. Save it to your books_users table.
id | book_id | user_id
1 1 1
2 2 2
3 2 3
If you have set your associations up correctly, when you request a user, all their books will be returned from the join table.
Your logic will need to deal with - number of books available,if a person can reserve more than one book at once...
http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm
Has an example.

CakePHP containable behaviour not firing

First time using Cake and its containable behaviour, but it's not working as expected ... or at all.
I'm trying to obtain a list of accessories for a product. Product model HABTM products (alias 'ProductRelation'). Join table is products_products which has two product ids - product_id and related_id. It's against this I want to pull the list of accessories (products driven from the related_id column) for a given product_id
In my Product model, I've added $actsAs = array('Containable');
And in my controller, a quick test of containable using reference from the cookbook fails to contain products at all, even without conditions.
debug($this->Product->find('all', array('contain' => 'ProductRelation')));
.. returns an array of every product in the db, with ALL related models - images, content tabs, ratings, reviews, pricing, etc I haven't tried applying any 'conditions' against this because the call as written should limit data to the product and it's ProductRelation data, according to the cookbook ...
Any tips?
It seems like you have recursive on. Try using the following:
debug($this->Product->find('all', array(
'contain' => 'ProductRelation',
'recursive' => -1
)));
If that works for you, you should start adding containable to the AppModel class and setting the recursive property to -1. This will ensure you only ever get the results you request.
NB: Cake does not join for HABTM, so you can not use ProductRelation in any conditions.

CakePHP how to create hasMany data without knowing the foreign key in one saveAll?

I was hoping to create and save the associated data like what I did with belongsTo data - the associated data are created on the fly and foreign ID is also generated and saved on the fly by a single call to saveAll or saveAssocated which has transaction built-in.
But this seems not the case for data in hasMany relationship. Take User and Comment as example. Comment has user_id as the foreign key.
It seems that I cannot save User $data by using single saveAll($data) on User
Array(
'name' => 'Jack',
'email' => 'jack#abc.com',
'Comment' => array(
array(
'title' => 'I like this article.'
)
)
)
I read some docs. It seems that I need to mention the user_id as the foreign key for the Comment data to create correctly.
If that's the case, since I don't have user ID until it's created, it seems that I need to code to let SAVE happen twice.
I really think that I am missing something. There should be a CAKE way for doing this.
This is done automatically by Cake as long as you follow the conventions and format the data accordingly. For hasMany associations, the main model data, and the associated model data, need to be set on string keys on the same level, like
array
(
'User' => array(),
'Comment' => array()
)
Also note that
The saveAll function is just a wrapper around the saveMany and
saveAssociated methods. it will inspect the data and determine what
type of save it should perform. If data is formatted in a numerical
indexed array, saveMany will be called, otherwise saveAssociated is
used.
This function receives the same options as the former two, and is
generally a backwards compatible function. It is recommended using
either saveMany or saveAssociated depending on the case.
So either will do.
Long story short, the model data needs to be separated and indexed by string keys, it's essentially the same format as a find() call would return it. That way Cake will know that it needs to save associated data, and will automatically insert the foreign key for the Comment records.
array
(
'User' => array
(
'name' => 'Jack',
'email' => 'jack#abc.com'
),
'Comment' => array
(
array
(
'title' => 'I like this article.'
)
)
)
See also
Cookook > Models > Saving Your Data > Associations: Linking Models Together > hasMany
Cookook > Models > Saving Your Data > Model::saveMany()
Cookook > Models > Saving Your Data > Model::saveAssociated()
Cookook > Models > Saving Your Data > Model::saveAll()

Relationship problem in Cakephp. How to fetch data?

I am trying to make a messages functionality similar to the facebook. Just the message thing and not facebook. A brief descriptions does like this.
1) There are a number of users ( user table) 2) One person can send a message to one or more than one person. 3) There can be multiple reply to the same message. 4) If its send to multiple people. All can reply and it is show to all of them.
Tables used
messages table
id
timestamp
sender_id
subject
message
due_date
urgent_flag
open_flag
reply_id
message_user (table)
id
timestamp
message_id
receiver_id
read_flag
The CakePHP relations are as follows :
Message Model
var $hasMany = array(
'MessageUser' => array(
'className' => 'MessageUser',
'foreignKey' => 'message_id',
)
);
var $belongsTo = array (
'User' => array (
'className' => 'User',
'foreignKey' => 'sender_id',
)
);
var $hasAndBelongsTo=array(
'Message' => array (
'className' => 'Message',
'foreignKey' => 'reply_id',
)
);
MessageUser Model
var $belongsTo = array (
'User' => array (
'className' => 'User',
'foreignKey' => 'receiver_id',
),
'Message' => array (
'className' => 'Message',
'foreignKey' => 'message_id'
)
);
Questions :
1) Is my approach correct ? Or the database schema needs to be revised. 2) If yes, How should I fetch the data for inbox ? This is a bit complex as I want to show the conversation for those messages which people has sent me.
For example, user 1 send message to user 2. User 2 adds 2 replies to the same. Then users 1's inbox should show only 1 message. and when I open it. it will show the previous msgs as well.. (this is similar to facebook)
One more problem which I see here is, How to delete messages ? Suppose user 1 deletes a message it should not show anything in his inbox. but user 2 can see the whole conversation which he had.
WRT your schema, I would only set the relationships in the direction that you need to access them. Thus, if you don't need to ever access the User given a Message, don't link messages back to users. It can create some recursion problems where your models will automatically fetch way too much data, because you have a circular loop (User hasMany Message, Message HasMany User, etc.) That's actually what the HABTM relationship is, so use that instead of hasMany (if you want it to be a bi-directional relationship).
My comment mentioned tree behavior. Simply put, it allows you to easily store heirarchical data into a relational database table. I won't repeat the manual, but check out http://book.cakephp.org/view/91/Tree and google around for examples. I'm pretty sure this is what you want to use for threaded replies.
One further word of caution -- if you're going to use this with a serious user base, run some load tests on this part of your database. I'm not sure how well TreeBehavior would work with millions of rows on a cheap server.

Resources