How do I filter deep associations in CakePHP

前端 未结 4 806
谎友^
谎友^ 2021-01-13 01:24

I have the following tables: binders, docs, users, docs_users. Doc belongsTo Binder, Doc hasAndBelongsToMany User.

I want to get binders and their associated docs f

相关标签:
4条回答
  • 2021-01-13 01:56

    These are a few of the options available for doing deep finds on data in CakePHP:

    • https://github.com/Terr/linkable/wiki
    • http://mark-story.com/posts/view/using-bindmodel-to-get-to-deep-relations
    • http://bakery.cakephp.org/articles/view/quick-tip-doing-ad-hoc-joins-in-model-find
    0 讨论(0)
  • 2021-01-13 02:00

    Here's the final solution I came up with based on all of the great feedback I got. I think this is an elegant solution that can be reused in any scenario where deep associations are required.

    In the binder_controller I unbound the Doc model, and bound it back using the finderQuery to select only the Docs that a user has permission to see. Then in joined the binders_users table selecting only the binders that users have permissions to.

    Thank you everyone for all your help!

    $this->Binder->unbindModel(array('hasMany' => array('Doc')));
    $this->Binder->bindModel(
        array('hasMany' => array(
                'Doc' => array(
                    'className' => 'Doc',
                    'foreignKey' => 'binder_id',
                    'dependent' => false,
                    'finderQuery' => 'SELECT Doc.* FROM docs AS Doc INNER JOIN docs_users AS DocsUser ON DocsUser.doc_id = Doc.id AND DocsUser.user_id = ' . $this->Auth->user('id')
                )
            )
        )
    );
    
    $binders = $this->Binder->find( 
        'all',                  
        array( 
            'joins' => array(
                array( 
                    'table' => 'binders_users', 
                    'alias' => 'BindersUser', 
                    'type' => 'inner', 
                    'foreignKey' => false, 
                    'conditions'=> array(
                        'BindersUser.binder_id = Binder.id',
                        'BindersUser.user_id = ' . $this->Auth->user('id')
                    )
                )               
            )
        )
    );
    

    More on binding/unbinding models

    0 讨论(0)
  • 2021-01-13 02:16

    On this line, you need to tell Cake which Model's id you are talking about:

    'conditions' => array('id = "17"')
    

    e.g. DocsUser.id

    ...and you don't use recursive with containable. Get rid of it.

    0 讨论(0)
  • 2021-01-13 02:19

    Have you tried coming in from a user perspective?

    $this->Binder->Doc->User->Behaviors->attach('Containable');
    $this->Binder->Doc->User->contain(array('Doc'=>'Binder'));
    $user = $this->Binder->Doc->User->find('all',array('conditions'=>'User.id'=>$user_id));
    

    The 'DocsUser' association should be detected anyway.

    From a Binders perspective maybe

    In your Binders MODEL add ( please check table, key and model names in case I made a typo )

    function getBindersByUserSql($user_id)
        {       
            $dbo = $this->getDataSource();
            $subQuery = $dbo->buildStatement(
                array(
                        'fields' => array('DISTINCT(Doc.binder_id)'),
                        'table' => "docs_users",                                       
                        'joins' => array(
                                    array('table' => 'users',
                                        'alias' => 'User',
                                        'type' => 'INNER',
                                        'conditions' => array('DocsUser.user_id = User.id')
                                    ),
                                    array('table' => 'docs',
                                        'alias' => 'Doc',
                                        'type' => 'INNER',
                                        'conditions' => array('Doc.id = DocsUser.doc_id')
                                    )
                ),
                        'alias'=>"DocsUser",                                            
                        'conditions' => array("User.id"=>$user_id),
                        'order' => null,
                        'group' => "Doc.binder_id"
                        ),
                        $this
                        );
            return $dbo->expression($subQuery);
        }
    

    Then in your binders CONTROLLER try

    $this->Binder->Behaviors->attach('Containable');
    $this->Binder->contain(array('Doc'));
    $conditions = array();
    $conditions = $this->Binder->getBindersByUserSql($this->Auth->user('id'));
    $binders = $this->Binder->find('all',array('conditions'=>$conditions)));
    

    Any good?

    0 讨论(0)
提交回复
热议问题