CakePHP: Using Layered Hidden Behavior

I've been trying to use Containable Behavior in CakePHP for quite some time, but I can't get it to work as I expected.

My application is different, but for simplicity I will give this example. Say I have a forum with topics and actions, and the activity can be rated. General ratios:

Forum: hasMany [Topic]
Topic: belongs to [Forum], hasMany [Activity]
Activity: belongs to [Thread], hasMany [Rating]
Rating: owned by [Activity]

I want to achieve, using the find method, to get all the ratings performed on a particular forum. I have to do the following:

$this->Rating->find('count', array( 'contain' => array( 'Activity' => array( 'Thread' ) ), 'conditions' => array( 'Thread.forum_id' => 1 ) )); 

But query result:

 SELECT COUNT(*) AS `count` FROM `ratings` AS `Rating` LEFT JOIN `activities` AS `Activity` ON (`Rating`.`activity_id` = `Activity`.`id`) WHERE `Thread`.`forum_id` = 1; 

I accomplished this using the Connections option, but it is more complex, and I have to use this peculiar action in many situations.

All files associated with the example can be found here: http://dl.dropbox.com/u/3285746/StackOverflow-ContainableBehavior.rar

thanks

Update 11/23/2011

After studying the structure and thanks to the answers of Moz Morris and api55, I found the source of the problem.

The main problem was that since I understood CakePHP, I thought every time it asks for the use of joins. The fact is that this is not so, the real operation that he would perform to get the result that I was looking for would be something like this:

 SELECT * FROM Rating JOIN Activity... SELECT * FROM Activity JOIN Thread... SELECT * FROM Activity JOIN Thread... ... 

Bearing in mind that he would execute the request to get all the actions, and then for each action execute the request to receive the threads ... My approach did not work not because of the incorrect use of Containable Behavior, but because the condition variant was applied to all requests and, firstly, it crashed due to the lack of a thread table. Having discovered this, there are two possible solutions:

  • As api55 said, using the conditions inside the 'contain' array, he would apply them only to queries using the Thread table. But the problem persists, because we have too many requests.

  • As Moz Morris said, linking the Thread model to the rating will also work, and it will execute one request that we want. The problem is that I see it as a patch that skips the relationship between the two models and does not follow the CakePHP philosophy.

I placed the api55 solution as correct, because it solves the specific problem I had, but both give a solution to the problem.

+6
source share
2 answers

First of all, you put the variable actAsableable in appModel ?? without it, this beahaviour will not work at all (I see that it does not work correctly, since it did not join the Thread table)

I would do it from above, I mean from the forum, so you select your forum (they donโ€™t need that you want a forum or thread) and get your entire rating, if you do not have a rating, you will get the rating key blank.

something like that

Appmodel

 public $actsAs = array('Containable'); 

rating controller

  $this->Rating->Activity->Thread->Forum->find('count', array( 'contain' => array( 'Thread' => array( 'Activity' => array( 'Rating' => array ( 'fields' => array ( 'Rating.*' ) ) ) ) ), 'conditions' => array( 'Forum.id' => 1 ) )); 

Then, if you only need the value in the rating table, just use Set: extract to get an array of that value.

As you did, IT SHOULD work anyway, but I try not to use forum_id there, but in conditions inside this type

 'contain' => array( 'Activity' => array( 'Thread' => array( 'conditions' => array('Thread.forum_id' => 1) ) ) ), 

Also, never forget that the actAs variable in the model uses pent-up behavior (or in the application model)

+5
source

Whist I like the api55 solution, I think the results are a little dirty - it depends on what you intend to do with the data that I think.

I assume that when you said using the join method, you were talking about using this method:

 $this->Rating->bindModel(array( 'belongsTo' => array( 'Thread' => array( 'foreignKey' => false, 'conditions' => 'Thread.id = Activity.thread_id', ), 'Forum' => array( 'foreignKey' => false, 'conditions' => 'Forum.id = Thread.forum_id' ) ) )); $ratings = $this->Rating->find('all', array( 'conditions' => array( 'Forum.id' => 1 // insert forum id here ) )); 

This seems a little cleaner to me, and you don't have to worry about using pent-up behavior in your AppModel. Worth considering.

+2
source

Source: https://habr.com/ru/post/902103/


All Articles