2010-09-01 111 views
1

我想知道是否可以在使用登录用户的ID的模型中创建hasMany关系。CakePHP中的其他模型的HasMany关系和ID

例如: 一个提示有很多投票(来自不同的用户)。这很容易:

public $hasMany = array(
    'TipVoting' => array(
     'className' => 'TipVoting', 
     'foreignKey' => 'tip_id', 
     'dependent' => false, 
     'conditions' => '', 
     'fields' => '', 
     'order' => '', 
     'limit' => '', 
     'offset' => '', 
     'exclusive' => '', 
     'finderQuery' => '', 
     'counterQuery' => '' 
    )); 

现在我想获得所有提示,但想知道登录用户是否已经投票了此提示。所以我想创建一个Realtionship,如下所示:

public $hasMany = array(
    'MyTipVoting' => array(
     'className' => 'TipVoting', 
     'foreignKey' => 'tip_id', 
     'dependent' => false, 
     'conditions' => array('TipVoting.user_id' => $loggedinUser_id), 
     'fields' => '', 
     'order' => '', 
     'limit' => '', 
     'offset' => '', 
     'exclusive' => '', 
     'finderQuery' => '', 
     'counterQuery' => '' 
    ) 
); 

如何将$ loggedinUser_id加入此模型?或者这是实施这个问题的不好方法?我应该去找一个TipVoting模型的单独的发现吗?

任何想法?

谢谢!

回答

2

使用可容纳的行为。 http://book.cakephp.org/view/474/Containable

你不想定义不同的关系,你只是希望能够通过关联的标准过滤。 Containable将允许你这样做。

只用TipVoting关系,在你的模型做到这一点:在你的控制器动作

var $actsAs = array('Containable'); 

做到这一点:

$this->TipVoting->find('all', array( 
'contain' => array( 
    'Vote' => array( 
    'conditions' => array( 
     'TipVoting.user_id' => $this->Auth->User('id')), 
    'order' => 'TipVoting.id DESC'))); 
+0

男人,你让我的一天!感谢您指出了这一点。这正是我所期待的! 这是我对我的问题的解决方案: $ this-> Tip-> find('all',array( 'contains'=> array('TipVoting'=> array( 'conditions'=> array(' TipVoting.user_id'=> $ this-> Auth-> user('id'))) ) )); 再次感谢! – chris 2010-09-02 09:02:11

+0

没问题。 Containable行为对于使用CakePHP非常重要,应该在手册中再强调一下。另一个令人敬畏的Cake类是Set - 它允许您将几个Cake样式的数组合并在一起,并基于不同的键合并。 – 2010-09-02 15:25:03

0

如果我理解这个问题,你真正之后一种定义条件一次而不是一种定义连接特定条件的方法。 Containable行为将处理后者,但不是前者。为此...

我不知道有什么方法可以在联合定义中使用变量值。由于这些是类变量,我怀疑它不能完成(声明:我没有尝试过)。在模型层面上尝试访问通常会话值(授权用户)的复杂性也会增加 - 这是严格意义上的MVC no-no。

我所做的,以满足类似的需求是一个事物的组合如下:

我用我的AppController转发身份验证的用户信息:

# AppController 
# You may or may not want to use the conditional 
if(!empty($this->data)) { 
    $this->data['User'] = $this->Auth->user(); 
} 

在模型中,创建一个beforeFind()回调,将修改查询结构:

# Your model, e.g. TipVoting 
# The data[] array will probably be keyed differently 
public function beforeFind($query) { 
    if(array_key_exists('active', $this->_schema)) { 
    $conditions = !empty($query['conditions']) ? $query['conditions'] : array(); 

    if(!is_array($conditions)) { 
     $conditions = array($conditions); 
    } 

    if(!isset ($conditions['user_id']) && !isset($conditions[$this->alias . '.user_id'])) { 
     $conditions[$this->alias . '.user_id'] = $this->data['User']['Administrator']; 
    } 

    $query['conditions'] = $conditions; 
    } 

    return $query; 
} 

此代码只是一个片段,满足需要类似给你的,所以它可能不会直接工作,但它应该让你知道什么是可能的,我认为它甚至可能非常接近你所追求的。请注意,您可能需要在这里和那里进行一些更改。

关键在于通过将会话信息显式转发给模型(而不是让模型直接访问它),同时将查询条件设置为每次使用会话值时保留“正确的”MVC结构从模型中检索,除非已经涉及以用户为中心的条件。

这不适合你的追求,但不应该花太长的时间才能根据你的需求量身定做。

0

尝试使用appControllers beforeFilter中的bindModel。

... 
public function beforeFilter(){ 
    parent::beforeFilter(); 
    if($this->Auth->user()){ 
     $this->User->bindModel(
      'hasMany' => array(
       'MyTipVoting' => array(
        'className' => 'TipVoting', 
        'foreignKey' => 'tip_id', 
        'conditions' => array(
         'MyTipVoting.user_id' => $this->Auth->user('id'), 
         //note the use of the aliased name here, not TipVoting but MyTipVoting 
         ... 
        ), 
        ... 
       ), 
       ... 
      ), 
     ); 
    } 
}