Сброс relations при unsetAttributes

Общие вопросы по использованию фреймворка. Если не знаете как что-то сделать и это про Yii, вам сюда.
Закрыто
Archaron
Сообщения: 7
Зарегистрирован: 2012.02.13, 02:26

Сброс relations при unsetAttributes

Сообщение Archaron »

Подскажите пожалуйста, верна ли такая логика работы:

есть моделька заказа Order, в ней релейшен

Код: Выделить всё

            'user' => array(self::BELONGS_TO, 'User', 'uid'),
 
в контроллере делаем вот так

Код: Выделить всё

// Получили модельку из базы по какому-то идишнику
$model = Order::findByPk(...);

echo $model-> uid;  // вывело допустим uid = 10
echo $model-> user-> id;  // исправно подтянуло User с Id=10 ( Order->uid ) и вывело 10 

// А теперь самое интересное - меняем в заказе uid
$model-> uid = 999; 
echo $model-> user-> id;  // выводит 10, хотя по логике должно подтянуть новую модельку User с ид = 999

// Очищаем атрибуты
$model-> unsetAttributes();
echo $model-> uid; // исправно выводит отсутствие значения
echo $model-> user-> id; // все еще выводит 10

// А если сделать так, то все работает как положено, привязанная моделька обновляется
unset($model-> user);
$model-> uid = 999; 
echo $model-> user-> id; // выводит 999

 
Возможно я не прав, но мне кажется логичным при изменении атрибута модельки убивать кеш релейшена.
Аватара пользователя
because
Сообщения: 689
Зарегистрирован: 2010.09.30, 22:01

Re: Сброс relations при unsetAttributes

Сообщение because »

такая логика неверна, одна запись - один объект, нужно опять выбрать методом find и подтягивать нужную связь
RTFM !
Archaron
Сообщения: 7
Зарегистрирован: 2012.02.13, 02:26

Re: Сброс relations при unsetAttributes

Сообщение Archaron »

Ну как бы все верно, одна запись в базе - один объект. Но если у этого объекта меняется атрибут, который участвует в связи - разве он не должен за собой тянуть новую связь?

Код: Выделить всё

$model = new ARModel('search');
$related_object = $model-> relation;

$model-> relation_id = NEW_ID;
$related_object = $model-> relation;
Разве $related_object не должен стать объектом, соответствующим НОВОМУ id ? Сразу образуется несоответствие ключа и связанного объекта.
Аватара пользователя
andy_s
Сообщения: 127
Зарегистрирован: 2012.01.22, 13:15

Re: Сброс relations при unsetAttributes

Сообщение andy_s »

Метод getRelated() не будет делать повторный запрос к БД, если связанные данные уже выбраны, на изменения значений атрибутов он тоже никак не реагирует. Попробуйте передать в качестве второго аргумента true.
Archaron
Сообщения: 7
Зарегистрирован: 2012.02.13, 02:26

Re: Сброс relations при unsetAttributes

Сообщение Archaron »

andy_s писал(а):Метод getRelated() не будет делать повторный запрос к БД, если связанные данные уже выбраны, на изменения значений атрибутов он тоже никак не реагирует. Попробуйте передать в качестве второго аргумента true.
Т.е. в таком случае пользоваться именно ф-ей, вместо прямого получения $model-> relation, ясно. А есть какие-либо особенности или ограничения, которые не позволяют сбрасывать кеш при смене атрибута? По мне так было бы очень удобно. Но если это принципиально так - ладно.
Аватара пользователя
andy_s
Сообщения: 127
Зарегистрирован: 2012.01.22, 13:15

Re: Сброс relations при unsetAttributes

Сообщение andy_s »

Archaron писал(а):Т.е. в таком случае пользоваться именно ф-ей, вместо прямого получения $model-> relation, ясно. А есть какие-либо особенности или ограничения, которые не позволяют сбрасывать кеш при смене атрибута? По мне так было бы очень удобно. Но если это принципиально так - ладно.
Тут, как говорится, "овчинка не стоит выделки". Проще воспользоваться методом явно, чем городить совсем неочевидные зависимости (которых может вовсе не быть) между сменой первичного ключа и загрузкой связанных объектов.
TM123
Сообщения: 608
Зарегистрирован: 2011.06.09, 11:18

Re: Сброс relations при unsetAttributes

Сообщение TM123 »

Утренее сообщение не сохранилось, так что пишу еще раз.

Я не понял, почему автор при изменении данных вызывает save, а при изменении фильтров поиска не считает нужным сказать еще раз find? Откуда фреймворк знает с какой целью вы поменяли значения полей в модели, то ли вы решили их поменять и сохранить, а то ли вы собираетесь просто поискать с новыми условиями?
Archaron
Сообщения: 7
Зарегистрирован: 2012.02.13, 02:26

Re: Сброс relations при unsetAttributes

Сообщение Archaron »

andy_s писал(а): Тут, как говорится, "овчинка не стоит выделки". Проще воспользоваться методом явно, чем городить совсем неочевидные зависимости (которых может вовсе не быть) между сменой первичного ключа и загрузкой связанных объектов.
Почему первичного ключа? Первичный ключ модельки основной не меняем какраз. Понятное дело что смена основного идишника подразумевает другой объект совершенно и его именно надо пересоздать по find или иначе. Я говорю какраз о смене именно атрибута одного и того же объекта. Мало того - ничего делать то собственно и не нужно, как я вижу, отношения кешируются в массив _relations, но unsetAttributes к примеру, это обычный
foreach () $attr = null;. Почему бы не сделать там же $this-> _relations=array(); ?

Код: Выделить всё

abstract class CActiveRecord extends CModel
{
... 
       private $_related=array();       // attribute name => related objects
....
....
    public function __unset($name)
    {
                ... 
               unset($this->_related[$name]);   // Но вот тут-то к примеру, спокойно делается unset?
         }

    public function unsetAttributes($names=null)
    {
        if($names===null)
            $names=$this->attributeNames();
        foreach($names as $name)
            $this->$name=null;

                 // почему бы здесь не сделать вот так? Таким образом не будет "залипать" кеш
                 $this-> _related = array();
    }
}
тоже самое как мне кажется хорошо сделать в setAttributes а также в __set делать просто unset кеша связи изменяемого атрибута если он участвует в связи. ( uid -> unset ($this-> _related[user]), post_id -> unset ($this-> _related[post]) итд ).

Почему мне кажется что это важно? Приведу пример

Код: Выделить всё

  // допустим мы сохраняем новый пост
  $model = new Post();   // создаем новый пост
  $model-> attributes = $_POST['post']; // присваиваем атрибуты
  $model-> save(); // сохранили

  $model-> user-> sendNotification("Пост сохранен");  // просто что-то делаем с притянутым за uid пользователем, который автор поста
  
   // и тут я захотел создать точно такой же пост одновременно от другого пользователя.
   // Что, мне повторять весь предыдущий код? Проще кажется просто поменять uid
   $model-> uid =  ADMIN_USER_ID; // не важно, просто от имени другого юзера
   $model-> save();  // Ага, все сохранили
   $model-> user-> sendNotification("Пост-перепост!"); // Я логично предполагаю что  ф-я вызовется для ADMIN_USER_ID, но вот облом - она вызывается для старого пользователя, не взирая на то, что он уже давно не тот
 
   // получается что каждый раз надо делать 
   $model-> getRelated('user', false)-> sendNotification("xxxx");   // мелочь, а неприятно и не очевидно!

   // или же явным образом сбрасывать кеш, тогда сразу резко $model-> user становится тем, кем надо
   unset($model-> user);
  
Archaron
Сообщения: 7
Зарегистрирован: 2012.02.13, 02:26

Re: Сброс relations при unsetAttributes

Сообщение Archaron »

TM123 писал(а):Откуда фреймворк знает с какой целью вы поменяли значения полей в модели, то ли вы решили их поменять и сохранить, а то ли вы собираетесь просто поискать с новыми условиями?
А какая ему разница, зачем я поменял поля модели? Find это просто так для примера, вообще не важно на самом деле. Сейчас получается что модель как-то совершенно статична местами. Я меняю поле - и хочу получить новое значение связи вот и все. А в данный момент я получаю при полной очистке всех атрибутов или их изменении - какие-то левые связи в кеше. Вопрос - если внешний ключ = NULL, какой внешней записи он соответствует? Верно - никакой. Второй вопрос - а откуда тогда берется связь? NULL --> Object() ? Было бы логично, если бы при установке внешнего ключа в NULL ( не важно какой связи ) эта связь выдавала бы NULL а не невесть откуда взявшееся значение, оставшееся с момента до очистки.
Аватара пользователя
because
Сообщения: 689
Зарегистрирован: 2010.09.30, 22:01

Re: Сброс relations при unsetAttributes

Сообщение because »

Archaron писал(а): Почему мне кажется что это важно? Приведу пример

Код: Выделить всё

  // допустим мы сохраняем новый пост
  $model = new Post();   // создаем новый пост
  $model-> attributes = $_POST['post']; // присваиваем атрибуты
  $model-> save(); // сохранили

  $model-> user-> sendNotification("Пост сохранен");  // просто что-то делаем с притянутым за uid пользователем, который автор поста
  
   // и тут я захотел создать точно такой же пост одновременно от другого пользователя.
   // Что, мне повторять весь предыдущий код? Проще кажется просто поменять uid
   $model-> uid =  ADMIN_USER_ID; // не важно, просто от имени другого юзера
   $model-> save();  // Ага, все сохранили
   $model-> user-> sendNotification("Пост-перепост!"); // Я логично предполагаю что  ф-я вызовется для ADMIN_USER_ID, но вот облом - она вызывается для старого пользователя, не взирая на то, что он уже давно не тот
 
   // получается что каждый раз надо делать 
   $model-> getRelated('user', false)-> sendNotification("xxxx");   // мелочь, а неприятно и не очевидно!

   // или же явным образом сбрасывать кеш, тогда сразу резко $model-> user становится тем, кем надо
   unset($model-> user);
  
Каким образом в данном определить, что вы хотите сделать - обновить текущую запись(модель) или создать новую. Поведение не очевидно.
Можно попробовать указать так:

Код: Выделить всё

$model->isNewRecord = true;
$model->uid = $id;
$model->save();
 
RTFM !
Archaron
Сообщения: 7
Зарегистрирован: 2012.02.13, 02:26

Re: Сброс relations при unsetAttributes

Сообщение Archaron »

because писал(а): Каким образом в данном определить, что вы хотите сделать - обновить текущую запись(модель) или создать новую. Поведение не очевидно.
Нет, запись тут вообще не причем, не нужно угадывать.

Код: Выделить всё

$model = new Post();     

$model-> relation_id = 123;
vardump($model-> reation );   // Object ( [uid]= 123 ....)

$model-> relation_id = 234;
vardump($model-> reation );   // Object ( [uid]= 123 ....)    Почему 123 а не 234? Разве не логично обновить? 
                                             //Или это принципиальные фундаментальные ограничения?

$model-> relation_id = null;
vardump($model-> reation );   // Object ( [uid]= 123 ....)   Откуда?  Если relation_ID нулл, почему там объект?

 
Аватара пользователя
andy_s
Сообщения: 127
Зарегистрирован: 2012.01.22, 13:15

Re: Сброс relations при unsetAttributes

Сообщение andy_s »

По определению объект ActiveRecord соответствует только одной строке таблицы. Вы пытаетесь нарушить это правило, используя один и тот же объект (от изменения значения одного атрибута он другим не станет) для представления двух различных строк таблицы (у одной relation_id = 123, у другой 234, но не сразу оба варианта). Вы рассматриваете очень примитивный случай, и я уверен, что найдутся примеры, в которых поведение, предлагаемое вами, может принести только вред и путаницу.
Archaron
Сообщения: 7
Зарегистрирован: 2012.02.13, 02:26

Re: Сброс relations при unsetAttributes

Сообщение Archaron »

Хорошо, ясно, спасибо за обьяснение! Приму за правило значит - объект одноразовый.
Закрыто