For example, I have this relationship:
UserContact hasMany Contact
Contact hasOne Info
Contact hasMany Response
And I need to paginate Contact, so I use Containable:
$this->paginate = array(
'limit'=>50,
'page'=>$page,
'conditions' =>array('Contact.id'=>$id),
'contain'=>array(
'Response',
'Info'
)
);
I want to add search by Info.name, and by Response.description. It works perfect for Info.name, but it throws an error if I try using Response.description, saying that the column doesn’t exist.
Additionally, I tried changing the relationship to Contact hasOne Response, and then it filters correctly, but it only returns the first response and this is not the correct relationship.
So, for example, if I have a search key $filter I’d like to only return those Contacts that have a matching Info.name or at least one matching Response.description.
If you look at how CakePHP constructs SQL queries you’ll see that it generates contained “single” relationships (
hasOneandbelongsTo) as join clauses in the main query, and then it adds separate queries for contained “multiple” relationships.This makes filtering by a single relationship a breeze, as the related model’s table is already joined in the main query.
In order to filter by a multiple relationship you’ll have to create a subquery:
But you should only generate the subquery if you need to filter by a
Responsefield, otherwise you’ll filter out contacts that have no responses.PS. This code is too big and ugly to appear in the controller. For my projects I refactored it into
app_model.php, so that each model can generate its own subqueries:Then the code in your controller becomes: