Выборка по полю в ассоциативной таблице

Есть две таблицы связанные отношением Many Many

users - поля id, name

messages - поля id, text

users_messages - поля id_user, id_message, private

отношение в messages


'users'	=> array(self::MANY_MANY, 'Users', 'users_messages(id_messages,id_users)'),

метод в модели messages для того чтоб выбрать то что нам нужно


	public function searchUserMessages($user_id,$private=0)

	{


		$criteria=new CDbCriteria;

		$criteria->with= array('users');

		$criteria->together = true;

		$criteria->condition = 'users.id = :uId';

		$criteria->params = array(':uId'=>$user_id);

		if ($private)

		{

			$criteria->addInCondition('users.private',1);    // не понимаю как правильно написать это условие

		}

		return new CActiveDataProvider($this, array('criteria'=>$criteria,));

	}

Задача: выбрать из бд все messages пользователя user_id, для которых поле private в ассоциативной таблице равно 1

Дано… Задача … - это так в школах учитель выдает задания ученикам.

На технических форумах другая формула: Дано … Нужно … Пытался сделать… Ожидал … а получилось … подскажите что не так сделал.

Ну как я пытался я уже показал :) вот я не понимаю в relations нам нужно указывать эти дополнительные поля в ассоциативной таблице? или мы итак сможем к ним обратиться.

Ну если не понятно, то я ожидал увидеть миного messages.text на страничке, у которых поле private в ассоциативной таблице равно 1.

Все еще не указано что же у тебя получилось.

Глядя на код, кажется что все верно. Но я давно использовал отношения *-*и могу ошибаться.

Вообще что возвращает код ниже, какой объект или массив каких объектов?




$messages=Messages::model()->findByPK(1); //укажи id записи сообщения, к которому есть связанные данные

print_r($messages->users);



на самом деле там ещё маленькая ошибка

$criteria->addInCondition(‘users.private’,array(‘1’));

но всё равно не ясно как указать поле private в этом условии.

Просто после выполнения выдаёт ошибку, что поле users.private не найдено. причем, что бы я не писал вместо users например если t.private всё равно не может найти это поле.

Возможно нужно указать что-то в relations в модели?

модель messages:




public function relations()

{

   return array(

    'users'=>array(self::MANY_MANY,'Users','users_messages(id_messages,id_users)'),

   ),

}



модель users:




public function relations()

{

   return array(

     'messages' => array(self::MANY_MANY, 'Messages', 'users_messages(id_users, id_messages)'),

);

}



Как моделям дать понять что там есть поле private в ассоциативной таблице?

А сделаем выстрел наугад, users_messages.private не помогает?

Лучше процитируйте текст ошибки, может быть информация о том где именно не найдено поле "private" натолкнет на мысль.

Вообще в следующей версии вреймворка от отношения MANY_MANY собираются отказаться, как от излишне сложной в понимании. Будем тогда делать два отношения HAS_MANY. Кстати, может быть тебе стоит этим заняться уже сейчас, ведь отношение MANY_MANY подразумевает что между двумя таблицами существует третья, но модели для неё нет. А ты создай модель к таблице связи и связывай свои "messages" и "user_messages" с ней через HAS_MANY это должно помочь.

Лучше проще:


$criteria->addCondition('users.private=1');

Oшибка появляется, т.к. таблица users не содержит поля private. Надо либо изменить структуру бд, либо изменить запрос (возможно, используя through). Просмотрите текущий запрос в логах, чтобы иметь более четкое понимание какой sql формируется.

Да спасибо, сам к этому пришёл, совершенно верное решение.

а как сохранить поля в ассоциативной таблице?

когда пытаюсь сохранить так


$message->users_messages->private = 1;

то на этой строчке в отладке пишет


Indirect modification of overloaded property Messages::$users_messages has no effect

Почему оно не имеет эффекта и как правильно сохранить всё одним движением?

использую ESaveRelatedBehavior

метод saveWithRelated

Я впервые вижу ESaveRelatedBehavior. Беглый просмотр его примеров использования не показал что бы можно было использовать конструкцию


$message->users_messages->private = 1;

Подумайте сами, что такое "$message->users_messages" ? Это массив из AR записей. А "->private" это обращение к методу объекта. Т.е. вы пытаетесь обратиться к массиву объекту как к самому объекту.

Вот если в цикле пройтись по всем объектам массива и каждому установить ->private то это сработает.

а почему впервые то? сами пишите сохранение связанных таблиц? или что то более продвинутое существует?

То были единичные случаи, получалось обойтись циклом. Специальное расширение не искал.

когда пишу


$message->users_messages[0]->private = 1;

та же ошибка

PS мне собственно и нужен только первый элемент, так как связь many-many я сделал просто чтобы было куда развиваться.

PSPS короче сделал после сохранения $message, сохранение users_messages с заполением нужных полей в обход компонента.

Решение меня устраивает, но может кто-то знает как сделать более красиво

Вы бы скинули сюда SQL запрос, который получается с этим, может найдём куда можно копнуть


if ($private)

{

    $criteria->addInCondition('users.private',1);    // не понимаю как правильно написать это условие

}