Yii найти модели через отношения многих - PullRequest
6 голосов
/ 04 августа 2011

Я использую Yii и у меня есть 3 таблицы: пользователи, устройства с таблицей users_devices (user_id, device_id) для определения отношения MANY_MANY между ними.

Я ищу самый простой способ найти устройство по его идентификатору (devices.id), который принадлежит определенному пользователю (users.id) через ActiveRecord.

В этом сценарии REST API запрашивает устройство, но я хочу убедиться, что устройство принадлежит пользователю по соображениям безопасности.

Примерно такова идея:

$device = Devices::model()->findByPk($deviceId)->having(
    array('user_id' => $userId));

Заранее благодарен за любую помощь, я изучал это некоторое время и не могу найти элегантного решения.

Ответы [ 3 ]

7 голосов
/ 05 августа 2011

Получил некоторую помощь на форумах Yii, что привело меня к самому определению:

$device = Device::model()->with('users')->find(array(
    'condition' => 'user_id = :userId AND device_id=:deviceId',
    'params' => array(':userId' => Yii::app()->user->id, ':deviceId' => $_GET['id'])));
2 голосов
/ 05 августа 2011

Возьмите два.

в Device.php:

// creates a users property within a Device, a container of associated Users
public function relations()
    {
        return array(
            'users'=>array(self::MANY_MANY, 'User',  // don't use HAS_MANY
                'user_devices(user_id, device_id)'), // composite key assumed
        );
    }

затем найдите, если запрошенное устройство принадлежит запрашивающему пользователю:

$device = Device::model()->findByPk($deviceId);
if ( $device->users->findByPk($userId) == Null )
    $device = Null; 

ЭтоПохоже, это сработало бы, но неэффективно извлекало бы много ненужных записей пользователя, так как вы уже знаете, кто пользователь, и, вероятно, уже имеют его activeRecord.Чтобы избежать этой неэффективности, книга Yii Agile Development использует сырой SQL для запросов отношений M2M в родительской модели (Device.php):

// "Agile" uses a $user AR argument, you can use $userId instead
public function doesUserOwnDevice($userId) 
{
    $sql = "SELECT user_id FROM user_devices WHERE
    device_id=:deviceId AND user_id=:userId";
    $command = Yii::app()->db->createCommand($sql);
    $command->bindValue(":deviceId", $this->id, PDO::PARAM_INT);
    $command->bindValue(":userId", $userId, PDO::PARAM_INT);
    return $command->execute()==1 ? true : false;
}

Я использовал Device вместо Devices для именимодель (аналогично device для названия таблицы).Рефакторинг, если вырезать и вставить.Аналогично для User.Аналогично, для пропущенного префикса "tbl_".

1 голос
/ 05 августа 2011

Вам нужно использовать AR?

Я всегда предпочитаю использовать построитель запросов при работе со сложными операторами ...

т.е.

$user = Yii::app()->db->createCommand()
    ->select('id, username, profile')
    ->from('tbl_user u')
    ->join('tbl_profile p', 'u.id=p.user_id')
    ->where('id=:id', array(':id'=>$id))
    ->queryRow();
...