Ашманные отношения и идентификатор от другой модели в CakePhp
-
26-09-2019 - |
Вопрос
Мне интересно, можно ли создать асманистые отношения в модели, которая использует идентификатор зарегистрированного пользователя.
Пример: один совет имеет много голосов (от разных пользователей). Это просто:
public $hasMany = array(
'TipVoting' => array(
'className' => 'TipVoting',
'foreignKey' => 'tip_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
));
Теперь я хочу получить все советы, но хотите знать, проголосовал ли вошедший в пользовательский пользователь. Поэтому я хотел бы создать фритий, который выглядит так:
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' => ''
)
);
Как мне получить $ loggugedinuser_id в эту модель? Или это плохой способ реализации этого вопроса? Должен ли я лучше пойти на отдельную находку в модели TipVoting?
Есть идеи?
Спасибо!
Решение
Используйте содержательное поведение. 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' ) ) );
Другие советы
Если я понимаю вопрос, что вы на самом деле после того, как это способ определить состояние однажды а не способ определить конкретное соединение. То 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, явно пересылаю информацию о сеансе обратной модели (вместо того, чтобы просить модель доступа к ней напрямую), при настройке условий запроса для использования значения сеанса каждый раз, когда каждый раз записи из модели извлекается, если у пользовательского назначения уже не участвует.
Это не идеально подходит для того, что вы после того, как вы должны занимать слишком долго, чтобы адаптировать его к вашим потребностям.
Попробуйте использовать BindModel из AppControllers Fromfilter.
...
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
...
),
...
),
...
),
);
}
}