来自CakePHP中其他模型的HasMany关系和ID

时间:2010-09-01 15:53:02

标签: cakephp cakephp-1.3

我想知道是否可以在模型中创建一个使用登录用户ID的hasMany关系。

实施例: 一个提示有很多投票(来自不同的用户)。这很简单:

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模型中单独寻找?

有什么想法吗?

谢谢!

3 个答案:

答案 0 :(得分:2)

使用可包含的行为。 http://book.cakephp.org/view/474/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' ) ) );

答案 1 :(得分:0)

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

我不知道在连接定义中使用变量值的任何方法。由于这些是类变量,我怀疑它无法完成(免责声明:我还没试过)。您还有一个额外的复杂性,即尝试在模型级别访问通常为会话值(授权用户)的东西 - 最严格意义上的MVC禁忌。

我为满足类似需求而做的是以下各项的组合:

我使用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结构(而不​​是让模型直接访问它),同时将查询条件设置为每次使用会话值时使用会话值除非已涉及以用户为中心的条件,否则将检索模型。

它不适合你所追求的东西,但根据你的需要定制它不应该花太长时间。

答案 2 :(得分: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
                        ...
                    ),
                    ...
                ),
                ...
            ),
        );
    }
}