如何过滤 CakePHP 中的深层关联

发布于 2024-10-21 12:09:21 字数 2869 浏览 1 评论 0原文

我有以下表格:活页夹、文档、用户、docs_users。 Doc 属于 Binder,Doc hasAndBelongsToMany User。

我想获取当前登录用户的活页夹及其关联文档(docs_users 表中的关联 user_id)。

我尝试过 Containable 和 find('all') 以及联接、条件等,但我不知道如何删除来自与 docs_users 表中不关联的用户的文档。

这段代码不起作用:

$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')
                    )
                ),
                array( 
                    'table' => 'docs', 
                    'alias' => 'Doc', 
                    'type' => 'left', 
                    'foreignKey' => false, 
                    'conditions'=> array(
                        'Doc.binder_id = Binder.id',
                    )
                ),                          
                array( 
                    'table' => 'docs_users', 
                    'alias' => 'DocsUser', 
                    'type' => 'left', 
                    'foreignKey' => false, 
                    'conditions'=> array(
                        'DocsUser.doc_id = Doc.id',
                        'DocsUser.user_id = ' . $this->Auth->user('id')
                    )
                )           
            ),
            'recursive'=>0
        )
    );
$this->set('binders', $binders);

这个也不起作用:

$this->Binder->recursive = 2;
$this->Binder->Behaviors->attach('Containable');
$this->Binder->contain(array(
    'Branch',
    'Doc' => array(                     
        'User' => array(
            'DocsUser' => array(
                'conditions' => array('id = "17"')
            )
        )
    )
));
$binders = $this->Binder->find('all');

来自经验丰富的专业人士的任何帮助都会很棒!谢谢!

替代/简化解决方案?

如果我只想获取用户有权访问的活页夹,则此方法有效。简短而甜蜜。但是,它仍然会发送所有关联的文档,这不是我想要的行为。它只需要传递用户具有权限的文档(如前所述)。

$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')
                )
            )
        )
    )
);

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 for the user that is currently logged in (the associated user_id in the docs_users table).

I have tried Containable and find('all') with joins, conditions, etc. but I can't figure out how to remove the Docs that are from Users who are not associated in the docs_users table.

This code does NOT work:

$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')
                    )
                ),
                array( 
                    'table' => 'docs', 
                    'alias' => 'Doc', 
                    'type' => 'left', 
                    'foreignKey' => false, 
                    'conditions'=> array(
                        'Doc.binder_id = Binder.id',
                    )
                ),                          
                array( 
                    'table' => 'docs_users', 
                    'alias' => 'DocsUser', 
                    'type' => 'left', 
                    'foreignKey' => false, 
                    'conditions'=> array(
                        'DocsUser.doc_id = Doc.id',
                        'DocsUser.user_id = ' . $this->Auth->user('id')
                    )
                )           
            ),
            'recursive'=>0
        )
    );
$this->set('binders', $binders);

And neither does this:

$this->Binder->recursive = 2;
$this->Binder->Behaviors->attach('Containable');
$this->Binder->contain(array(
    'Branch',
    'Doc' => array(                     
        'User' => array(
            'DocsUser' => array(
                'conditions' => array('id = "17"')
            )
        )
    )
));
$binders = $this->Binder->find('all');

Any help from you seasoned pros would be great! Thanks!

Alternative/Simplified Solutions?

This works if I just want to get binders to which users have permissions. Short and sweet. However, it will still send ALL associated docs through, which is NOT the behavior I want. It needs to only pass on the docs to which the user has permissions (as described previously).

$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')
                )
            )
        )
    )
);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

暮倦 2024-10-28 12:09:21

这是我根据收到的所有反馈提出的最终解决方案。我认为这是一个优雅的解决方案,可以在任何需要深度关联的场景中重复使用。

在binder_controller中,我取消了Doc模型的绑定,并使用finderQuery将其绑定回来,以仅选择用户有权查看的文档。然后在加入的binders_users表中仅选择用户有权访问的活页夹。

感谢大家的帮助!

$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')
                )
            )               
        )
    )
);

有关 绑定/解除绑定模型

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

鹊巢 2024-10-28 12:09:21

在这一行中,您需要告诉 Cake 您正在谈论哪个模型的 id:

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

例如 DocsUser.id

...并且您不使用可包含的递归。摆脱它。

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.

却一份温柔 2024-10-28 12:09:21

您是否尝试过从用户角度切入?

$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));

无论如何,应该检测到“Doc​​sUser”关联。

从活页夹的角度来看,也许

在你的活页夹模型中添加(请检查表、键和模型名称,以防我打错字)

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);
    }

然后在你的活页夹控制器中尝试

$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)));

有什么好处吗?

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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文