rrd
rrd

Reputation: 1451

custom finder with matching in association definition?

I have two models: Contacts and Groups with belongsToMany association.

I want to get only that groups what is accessible for the contact. For this I have a custom finder.

public function findAccessible(Query $query, array $options){
    return $query
            ->where(['admin_user_id' => $options['User.id']])
            ->orWhere(['public' => true])
            ->matching('Users', function($q) use ($options){
                return $q->orWhere(['Users.id' => $options['User.id']]);
            });
}

So I can call to following and I will get what I want.

$accessibleGroups = $this->Contacts->Groups->find('accessible', ['User.id' => $this->Auth->user('id')]);

But if I have a contain, than it will give back all groups not just accessible ones.

$contact = $this->Contacts->get($id, [
        'contain' => ['Groups']
    ]);

How to limit the contain to accessible?

I can not add the custom finder to the table association definition's finder property, as I can not pass the $options there. Or can I?

Upvotes: 2

Views: 3999

Answers (1)

ndm
ndm

Reputation: 60463

Let me quote the docs and the tests (if you can't find something in the docs, the tests are often a useful source for information on how to do things).

http://book.cakephp.org/3.0/en/orm/table-objects.html#passing-conditions-to-contain

If you have defined some custom finder methods in your associated table, you can use them inside contain:

// Bring all articles, but only bring the comments that are approved and
// popular.
$query = $articles->find()->contain([
    'Comments' => function ($q) {
       return $q->find('approved')->find('popular');
    }
]);

In that scenario you could simply pass in the conditions in the find() call just like you are already doing.


http://book.cakephp.org/3.0/en/orm/table-objects.html#using-the-finder-option

https://github.com/cakephp/cakephp/blob/7fc4cfe3ae7d4c523331a44e2862bab5c8f44f1e/tests/TestCase/ORM/QueryTest.php#L2175

So there's also this "hidden" finder option that can be used instead of a callable:

$table->find('all')
    ->where(['Articles.author_id' => $authorId])
    ->contain([
        'Authors' => [
            'finder' => ['byAuthor' => ['author_id' => $authorId]]
        ]
    ]);

I guess it wouldn't hurt if the finder usage would be documented a little more detailed in the Cookbook, the docblock for Query::contain() is missing info about it too.

Upvotes: 6

Related Questions