WithRelatedBehavior

Выкладываем свои наработки
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

WithRelatedBehavior

Сообщение creocoder »

Разрабатываете крупные приложения? Надоели толстые и сложные контроллеры? Надоело вручную оборачивать в транзакции? Есть выход. Поведение, которое позволяет сохранять модель и все связанные модели с поддержкой всех типов связей при помощи нативного API, которое вы все уже хорошо знаете. Поддерживаются все виды ключей, в том числе композитные. Сайт проекта: https://github.com/yiiext/with-related-behavior. Документация есть там же и находится в процессе доработки. Поведение довольно объемное и сейчас там показаны не все возможности. Поэтому если есть вопросы — задавайте.

Unit тесты готовы. Подготавливаются к заливке на GitHub.

Пример использования:

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

$user=new User;
$user->name='Test';

$user->group=new Group;
$user->group->name='Test';

$tag1=new Tag;
$tag1->createdBy=$user;
$tag1->name='test1';
$tag2=new Tag;
$tag2->createdBy=$user;
$tag2->name='test2';
$tag3=new Tag;
$tag3->createdBy=$user;
$tag3->name='test3';

$article=new Article;
$article->title='Test';
$article->tags=array($tag1,$tag2,$tag3);

$comment1=new Comment;
$comment1->content='Test1';
$comment2=new Comment;
$comment2->content='Test2';
$comment3=new Comment;
$comment3->content='Test3';

$article->comments=array($comment1,$comment2,$comment3);

$article->createdBy=$user;

$article->withRelated->save(array(
    'comments',
    'tags'=>array('createdBy'),
    'createdBy'=>array(
        'id','group_id','name',
        'group'=>array('id','name'),
    ),
));
 
Последний раз редактировалось creocoder 2011.09.26, 19:48, всего редактировалось 2 раза.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: WithRelatedBehavior

Сообщение samdark »

Вот он, долгожданный save() для MANY_MANY и HAS_MANY. Пробуйте, отписывайтесь. Возможно, именно в этом виде оно попадёт в Yii2 или даже в Yii1.1.
Аватара пользователя
Svyatov
Сообщения: 459
Зарегистрирован: 2010.08.12, 14:50
Откуда: Санкт-Петербург
Контактная информация:

Re: WithRelatedBehavior

Сообщение Svyatov »

Документации не хватает или хотя бы пояснения финального формата массива для сохранения.
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: WithRelatedBehavior

Сообщение creocoder »

Формат массива для сохранения обратно совместим с $attributes. Суть его в следующем. Для классического save() в качестве параметра можно указать атрибуты модели. В данном случае можно указать как атрибуты, так и связи. Причем в случае связей можно также указать атрибуты и связи и так в глубину. Сейчас я распишу, где атрибуты, где связи в вышеприведенном примере:

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

$article->withRelated->save(array(
    'comments', //связь comments
    'tags'=>array('createdBy'), //связь tags, внутри массива связь createdBy связи tags
    'createdBy'=>array( //связь createdBy
        'id','group_id','name', //аттрибуты модели связи createdBy
        'group'=>array('id','name'), //связь group, внутри массива атрибуты модели связи group
    ),
)); 
В целом понять довольно просто, между связями и атрибутами отдельно взятой модели не может быть коллизий, поэтому формат для сохранения был минимизирован и оптимизирован. Пример приведен просто сразу мощный. В подавляющем большинстве случаев достаточно вызовов плана $article->withRelated(array('tags','comments')); Просто поведение может контролировать сохранение атрибутов не только для главной модели, но и для связи любой глубины.

P.S. Между атрибутами и связями есть небольшая разница в разрезе сохранения. Для классического save() если не указаны никакие атрибуты - то будут сохранены все. Здесь такой же подход. Но, что касается связей, то нужно конкретно указывать, какие необходимо сохранить вместе с моделью. Что касается атрибутов связей, то тут все также как для главной модели. Если не указаны - сохраняются все атрибуты связи.
Последний раз редактировалось creocoder 2011.09.26, 20:10, всего редактировалось 1 раз.
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: WithRelatedBehavior

Сообщение creocoder »

Sam Dark писал(а):Вот он, долгожданный save() для MANY_MANY и HAS_MANY.
А также для HAS_ONE и BELONGS_TO.
Аватара пользователя
RusAlex
Сообщения: 324
Зарегистрирован: 2010.08.29, 15:30

Re: WithRelatedBehavior

Сообщение RusAlex »

"спасибо" улетает в Тамбов.
Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: WithRelatedBehavior

Сообщение Ekstazi »

Молодец, уже и не надеялись!
Аватара пользователя
delvin
Сообщения: 85
Зарегистрирован: 2009.11.13, 15:29

Re: WithRelatedBehavior

Сообщение delvin »

Как раз, то что нужно для пары текущих проектов. Спасибо :)
Это, пожалуй, последние проекты которые пишу на пхп - как раз вовремя :)
После перехода на питон, аж глаза ломит от чтения кода на пхп :)
Аватара пользователя
xoma
Сообщения: 641
Зарегистрирован: 2009.04.02, 15:24
Откуда: Ногинск
Контактная информация:

Re: WithRelatedBehavior

Сообщение xoma »

Спасибо за проделанную работу!

Один вопросик: с through работает (бывает часто необходимо) ?
Аватара пользователя
Svyatov
Сообщения: 459
Зарегистрирован: 2010.08.12, 14:50
Откуда: Санкт-Петербург
Контактная информация:

Re: WithRelatedBehavior

Сообщение Svyatov »

creocoder, спасибо за объяснения, теперь все понятно. Отличное поведение, обязательно заюзаю в ближайшее время.
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: WithRelatedBehavior

Сообщение creocoder »

xoma писал(а):Один вопросик: с through работает (бывает часто необходимо) ?
Нет. Как вы себе это представляете? :) Опция `through` была создана с целью организации мостовых соединений сугубо в целях выборки, таким образом связи такого типа можно считать "ненатуральными". Сохранение связанных моделей работает только с натуральными связями, а не через мост. Да и смысл? Если есть `through`, то вероятность присутствия натуральной связи в модели очень высока, и даже если её там нет, то всегда можно добавить. Таким образом поддержка `through` не только не возможна, а просто не нужна. Я могу привести примеры, если необходимо, как сохранять в вашей ситуации(ях).

P.S. Обновилась немного документация.
Аватара пользователя
xoma
Сообщения: 641
Зарегистрирован: 2009.04.02, 15:24
Откуда: Ногинск
Контактная информация:

Re: WithRelatedBehavior

Сообщение xoma »

У меня примерно вот такая ситуация:

Есть модель Slide (слайд-шоу), есть модель Image (Изображения), для связи слайд-шоу и изображений есть модель и таблица ImageToSlide.

Пишу примерно вот такой код:

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


$model = Slide::model()->findByPk($id);

$model->i2s = new ImageToSlide;

$model->i2s->slideId = $model->id;

$model->i2s->image = new Image;

$model->i2s->image->setAttributes(array(
          'name' => "Slide_show_order_{$model->id}",
          'alt'  => "Slide_show_order_{$model->id}",
          'description' => "Slide_show_order_{$model->id}",
          'file' => $newName 
));

$model->withRelated->save(array('i2s' => array('image')))

 
Вот такой код у меня не работает (save возвращает true, но данные в базу не попадают) не подскажите что я не так делаю ?
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: WithRelatedBehavior

Сообщение creocoder »

Вот это:

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

$model->i2s->slideId = $model->id;
 
можно выкинуть сразу. Такие низкоуровневые вещи поведение берет на себя.

Попробуйте следующий код:

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

$model = Slide::model()->findByPk($id);
$model->i2s = new ImageToSlide;

$image = new Image;
$image->setAttributes(array(
          'name' => "Slide_show_order_{$model->id}",
          'alt'  => "Slide_show_order_{$model->id}",
          'description' => "Slide_show_order_{$model->id}",
          'file' => $newName 
));

$model->i2s->image=array($image);

$model->withRelated->save(array('i2s' => array('image')));
 
Если не заработает, приведите дамп всех трех моделей в теме. В любом случае спасибо за код, я доработаю расширение таким образом чтобы в случае подобного использования save() сразу выдавал Exception с описанием того, что не так. В данном случае здесь попытка присвоить $model->i2s->image одиночного значения, вместо массива.
Аватара пользователя
xoma
Сообщения: 641
Зарегистрирован: 2009.04.02, 15:24
Откуда: Ногинск
Контактная информация:

Re: WithRelatedBehavior

Сообщение xoma »

Спасибо за ответ, но я еще помучаю вас =)

Вот такой код

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

$model->i2s = new ImageToSlide;
$image = new Image;
$image->setAttributes(array(
             'name' => "Slide_show_order_{$model->id}",
             'alt'  => "Slide_show_order_{$model->id}",
             'description' => "Slide_show_order_{$model->id}",
             'file' => $newName 
));                            
$model->i2s->image=array($image);                                                            
if(!$model->withRelated->save(array('i2s' => array('image'))))
{
      Yii::app()->ajax->raw(array('error' => 'Ошибка сохранения данных!'));        
}
 
Результат не изменился, save возвращает true, но данные не сохраняются...

Дампы моделей вот в этом файлике http://narod.ru/disk/26681082001/models-dump.html
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: WithRelatedBehavior

Сообщение creocoder »

Нужны дампы не в виде CVarDumper::dump($models);, а содержимое файлов, чтобы разобраться в ситуации.
SpiLLeR
Сообщения: 350
Зарегистрирован: 2009.09.17, 16:47
Откуда: Санкт-Петербург
Контактная информация:

Re: WithRelatedBehavior

Сообщение SpiLLeR »

Возможно потому, что примеры в описание не корректны, метод save() принемает два параметра и первый из которых boolean, который отвечает за то, делать валидацию или нет. Сейчас с этим помучился. Если сделать ...->save(true, array(myRelationsAndFields)) - то все работает нормально.
Не рабочий вариант:

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

        if(!$good->withRelated->save(array('attributeValues'))) {
            var_dump($good->errors);
            foreach($good->attributeValues as $attributeValue)
                var_dump($attributeValue->errors);
        } 
Рабочий:

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

        if(!$good->withRelated->save(true, array('attributeValues'))) {
            var_dump($good->errors);
            foreach($good->attributeValues as $attributeValue)
                var_dump($attributeValue->errors);
        } 
Предупрежден - значит вооружен.
devKP.ru
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: WithRelatedBehavior

Сообщение creocoder »

SpiLLeR
Спасибо за замечание, документация на текущий момент в процессе правки. Действительно у save() другая сигнатура, подкорректирую документацию на эту тему.

P.S. Вероятнее всего, в недалеком будующем не придется указывать конкретные связи, которые требуется сохранить с основной моделью, что повысит удобство использования. Пока все упирается в текущую архитектуру AR.
SpiLLeR
Сообщения: 350
Зарегистрирован: 2009.09.17, 16:47
Откуда: Санкт-Петербург
Контактная информация:

Re: WithRelatedBehavior

Сообщение SpiLLeR »

Еще хочу отметь не рабочесть такой логики:
Есть сущность Товар и Значение Характеристики Товара(ЗХТ). Когда пытаемся вставить абсолютно новые значения, то все отлично. Но когда у нас существует Товар и мы к нему хотим добавить ЗХТ, то валиться с ошибкой на строке 407, в которой понятно как минимум, что fk не проставляются. Честно я не очень расскурил код, да и поздно уже поэтому решения пока не нашел. Очень жаль что за первое использование столько неточностей... очень буду рад если в скором времени это вылечится.
Предупрежден - значит вооружен.
devKP.ru
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: WithRelatedBehavior

Сообщение creocoder »

Ситуация о которой вы говорите маловероятна, тут есть вероятность неправильного использования. Расширение весьма неплохо оттестировано, на текущий момент после публикации была найдена одна незначительная ошибка в коде и пара ошибок в доке. Лучше всего приведите код, который приводит к ошибке, желательно с листингом моделей. Это поможет разобраться в ситуации. В случае если используется MySQL напишите какой используется тип таблиц (MyISAM, InnoDb).
SpiLLeR
Сообщения: 350
Зарегистрирован: 2009.09.17, 16:47
Откуда: Санкт-Петербург
Контактная информация:

Re: WithRelatedBehavior

Сообщение SpiLLeR »

Возможно, я действительно что-то не так делаю. Использую InnoDB
Вот код: http://pastebin.com/dv6FVaEZ
Предупрежден - значит вооружен.
devKP.ru
Ответить