Использование through в отношении MANY_MANY в Yii фреймворке.

Yiiframework 22 августа 2011 г., 15:32

С версии 1.1.7 в ActiveRecord Yii доступен новый параметр для настройки отношений в моделях. Имя этого параметра — through. В этой заметке хочу показать один из примеров для чего этот параметр можно использовать. Сразу скажу, что я сам еще не до конца разобрался с этим, так что могу что-то напутать и где-то ошибаться.



Предположим, что у нас есть модель «Сотрудник» — Employee, модель «Проект» — Project. Сотрудник может участвовать во многих проектах и в одном проекте может участвовать много сотрудников, следовательно между проектом и сотрудиком отношение «многие ко многим» (MANY_MANY в терминах Yii). Для простоты предположим, что сотрудник, как и проект имеет всего два поля: id и name.
Для связки сотрудников и проектов введем третью таблицу «Employee_to_Project», в которой будем хранить id сотрудника (emp_id) и id проекта (proj_id). Такой простой таблички достаточно для установки простой связи. Теперь предположим, что каждый сотрудник в рамках каждого проекта должен иметь какую-то должность (для простоты это будет просто текстовое поле). Для хранения должности, в таблицу-связку добавим еще одно поле «position». Таким образом таблица-связка будет состоять из 3-х полей: emp_id, proj_id, position. С таблицами разобрались, переходим к моделям. Для краткости буду показывать только необходимые для примера методы моделей.

Модель Employee:

<?php 
class Employee extends CActiveRecord 
{
	public function relations()
	{		
		return array(
			'projects' => array(self::MANY_MANY, 'Project','Employee_to_Project("emp_id","proj_id")'),			
		);
	}
}
?>


В этой моделе мы определили стандартное отношение MANY_MANY и теперь для получения пользователя со всеми его проектами необходимо выполнить вот такой код:

<?php  $user = Employee::model()->with('projects')->findByPk($id); ?>


"$user->projects" — будет содержать массив моделей Project (проектов, в которых участвует пользователь)

Казалось бы все хорошо, но возникает вопрос: как получить роль сотрудника в каждом из проектов? Роль хранится в таблице-связке, а массив «projects» содержит массив моделей Project — следовательно через модель Project эту самую роль получить не получится. Вот тут нам на помощь и приходит новый параметр through.

Изменим нашу модель следующим образом:

<?php 
class Employee extends CActiveRecord 
{
	public function relations()
	{		
		return array(
			'projectsRell' => array(self::HAS_MANY, 'Project','EmployeeToProject'),			
			'projects'     => array(self::HAS_MANY, 'Project','proj_id','through' => 'projectsRell'),			
		);
	}
}
?>


Что мы тут сделали:

1 Добавили отношение «projectsRell» (EmployeeToProject — модель для табличики Employee_to_Project)
2 В отношении projects тип отношения изменили с MANY_MANY на HAS_MANY
3 В отношении projects указали параметр «through» со значением «projectsRell» (projectsRell — отношение, определенное в пункте 1)

Обратите внимание на:

1 Вместо отношения MANY_MANY везде используется HAS_MANY.
2 В отношении projects, которое указывает на таблицу/модель Project в качестве ключа использовано поле «proj_id». Это поле в таблице Project отсутствует, но оно есть в таблице/моделе EmployeeToProject, на которую мы и указываем параметром «through» (через запись 'through' => 'projectsRell')

Как этим пользоваться?


<?php  $user = Employee::model()->with('projectsRell','projects')->findByPk($id); ?>

<?php foreach($user->projectsRell as $rel):?>
    <?php echo $rel->position; // получаем роли в проектах?>    
<?php endforeach;?>

<?php foreach($user->projects as $proj):?>
    <?php echo $proj->name; // получаем названия проектов ?>    
<?php endforeach;?>


Ссылки по теме:

www.yiiframework.com/doc/guide/1.1/en/database.arr#relational-query-with-through
www.yiiframework.ru/forum/viewtopic.php?f=6&t=3765
www.yiiframework.com/forum/index.php?/topic/22386-through-relational-query-problem/page__p__109539__hl__through
www.yiiframework.com/forum/index.php?/topic/22011-relational-query-with-through-explained/page__p__107745__hl__through

Юпи! — CMS на Yii – http://yupe.ru

Исходный код – https://github.com/yupe/yupe

Присоединяйтесь!

Теги: through yii xoma 0


Комментарии 4

xoma
xoma
спасибо, поправил!
griboff
griboff
Скажите, а к таблице Employee и Project надо добавить поля к примеру position для связи? Потому что не понятно как их фильтровать по полю position таблце Employee_to_Project.
xoma
xoma
Не совсем понял Ваш вопрос =(
griboff
griboff
Тупанул я. Все разобрался
Пожалуйста, авторизуйтесь или зарегистрируйтесь для комментирования!