WithRelatedBehavior

Выкладываем свои наработки
mlapko
Сообщения: 37
Зарегистрирован: 2012.06.03, 21:57

Re: WithRelatedBehavior

Сообщение mlapko »

Код теста абстрактный, но передаёт смысл

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

class FooBehavior
{
    public function events()
    {
        return array(
            'onAfterConstruct'=>'afterConstruct',
            'onBeforeValidate'=>'beforeValidate',
            'onAfterValidate'=>'afterValidate',
            'onBeforeSave'=>'beforeSave',
            'onAfterSave'=>'afterSave',
            'onBeforeDelete'=>'beforeDelete',
            'onAfterDelete'=>'afterDelete',
            'onBeforeFind'=>'beforeFind',
            'onAfterFind'=>'afterFind',
        );
    }
    
    protected function afterConstruct($event) {}

    protected function beforeValidate($event) {}

    protected function afterValidate($event) {}
    
    protected function beforeSave($event) {}

    protected function afterSave($event) {}

    protected function beforeDelete($event) {}

    protected function afterDelete($event) {}

    protected function beforeFind($event) {}

    protected function afterFind($event) {}
    
    public function attach()
    {
        $class = new ReflectionClass($this);
        foreach ($this->events() as $event => $handler) {
            if (!$class->getMethod($handler)->isProtected())
                echo $handler;
        }
    }    
}

class EmptyBehavior extends FooBehavior
{
    public function events() { return array(); }
}

class GeneralBehavior extends FooBehavior {}

// EmptyBehavior
$start = microtime(true);
for ($i = 0; $i < 1000; ++$i) {
    $object = new EmptyBehavior();
    $object->attach();
}
echo microtime(true) - $start, '<br/>';
// GeneralBehavior
$start = microtime(true);
for ($i = 0; $i < 1000; ++$i) {
    $object = new GeneralBehavior();
    $object->attach();
}
echo microtime(true) - $start;
 
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: WithRelatedBehavior

Сообщение creocoder »

Это только аттач. При реальной вставке/чтении записей время, которое будет затрачено на аттач станет незначительным. На трекере проводились реальные практические тесты. Таким образом незначительная потеря в скорости в общей картине при аттаче (за возможность не думать о перекрытии events()) это вполне допустимо.
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: WithRelatedBehavior

Сообщение slavcodev »

creocoder писал(а):
creocoder, отнаследуйтесь от CBehavior, повысит производительность, в вашем behavior'е CActiveRecordBehavior не нужен.
Во первых это было бы идеологически неправильно, во вторых в версии 1.1.13 появится мой и mc-bear фикс расхода памяти поведениями. Поэтому уже не актуально.
Что это за идеология такая? Мне кажется тебя запутали названия классов. Но нет ничего запрещающего использовать cbehavior с активными записями. учитывая что не юзается ни одно стандартное событие.
Жду Yii 3!
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: WithRelatedBehavior

Сообщение creocoder »

Что это за идеология такая? Мне кажется тебя запутали названия классов. Но нет ничего запрещающего использовать cbehavior с активными записями. учитывая что не юзается ни одно стандартное событие.
Сегодня не юзается, завтра юзается. ИМХО все поведения которые работают с AR должны наследовать CActiveRecordBehavior. Отсутствие событий это НЕ КРИТЕРИЙ делать у класса другого родителя. Тем более в целях какой то экономии на спичках. А после фикса это вообще уже не актуально.
Последний раз редактировалось creocoder 2012.11.19, 17:08, всего редактировалось 2 раза.
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: WithRelatedBehavior

Сообщение slavcodev »

creocoder писал(а):Сегодня не юзается, завтра юзается. ИМХО все поведения которые работают с AR должны наследовать CActiveRecordBehavior
Да ладно. Откуда такие выводы? Только потому что у СActiveRecord и CActiveRecordBehavior есть приставка у класса? Что помешает конкретно этому поведению, когда завтра будет юзатся ивенты, поменять родителя? Да и когда появится завтра другая логика, то и поведение будет уже другое.

ЗЫ: Я предпочитаю не назвать то что сделали с поведениями фиксом, скорее это хак. Для меня фикс - это когда проблему убирают, в данном случае просто придумали как ее обойти :)
Жду Yii 3!
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: WithRelatedBehavior

Сообщение creocoder »

Но нет ничего запрещающего использовать cbehavior с активными записями.
И что? Нет ничего запрещающего делать ещё много нехороших с точки зрения ООП вещей в Yii. С Zend философией я уверен, что юзер пытающийся так сделать получал бы exception с трехэтажным матом. Но у нас не Zend, совершенно другая философия по поводу обработки ошибок. Поэтому всё на совести разработчиков расширений и конечных пользователей. Но иногда, вот от таких предложений "сэкономить на спичках" я жалею, что у нас такая политика обработки ошибок.
Я предпочитаю не назвать то что сделали с поведениями фиксом, скорее это хак. Для меня фикс - это когда проблему убирают, в данном случае просто придумали как ее обойти
Проблему именно устранили, а не обошли.
karpo518
Сообщения: 120
Зарегистрирован: 2012.08.30, 20:05
Контактная информация:

Re: WithRelatedBehavior

Сообщение karpo518 »

creocoder Спасибо вам за расширение. С ним код обработки сложных форм сократился до приятного размера. Скажите, не планируете ли вы добавить в поведение подобный метод для инициализации? Было бы здорово передавать модели один массив для инициализации её и связанных моделей. Особенно изящно это решение может использоваться при обработке вложенных форм.
saygo
Сообщения: 48
Зарегистрирован: 2013.01.07, 09:55

Re: WithRelatedBehavior

Сообщение saygo »

Хороший Behavior, как раз искал нечто подобное, часть задачи решил. Теперь другая часть, может поможете.

Есть
Users{
contract_id (PK)
.............
}

и Ip{
id (PK)
user_id (contract_id из предыдущей таблицы)
ip
}

У одного юзера может быть несколько Ip (минимум 1)
в users _form добавил
$ips=CHtml::listData(Ip::model()->findAll('user_id=:user_id', array(':user_id' => $model->contract_id)), 'id', 'ip');
foreach($ips as $i=>$ip)
{
echo CHtml::TextField('ip['.$i.']',$ip);
}
echo CHtml::TextField('ip['.$i.']','');
Что выводит инпуты с существующими IP + 1 поле, если нужно добавить еще

Подскажите, что нужно поменять, чтобы на этих инпутах работала валидация из Ip (регулярка по правильности + unique(это между собой не обязательно, визуально видно дубликат при 1-3 IP)).
Правильно сформировать массив $_POST, который использовать потом в контроллере вместо

$ip1 = new Ip;
$ip1->ip = "192.168....";
$ip1->user_id = $model->contract_id;

$model->ip = array($ip1,$ip2....);
alexanoid
Сообщения: 79
Зарегистрирован: 2011.11.26, 21:48

Re: WithRelatedBehavior

Сообщение alexanoid »

непонятно, при помощи этого расширения можно делать только save новой модели или можно также сделать и update. Если да - то как ? Спасибо.
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: WithRelatedBehavior

Сообщение slavcodev »

а разве update это не частный случай save? ты вызываешь update? смысл?
Жду Yii 3!
alexanoid
Сообщения: 79
Зарегистрирован: 2011.11.26, 21:48

Re: WithRelatedBehavior

Сообщение alexanoid »

mc-bear писал(а):а разве update это не частный случай save? ты вызываешь update? смысл?
смысл в том, что я Java программист и например в одном из джавишных ORM под названием Hibernate используется три метода - save, update and saveOrUpdate()

По старой привычке я стал искать аналоги здесь и не нашел. Отсюда и возник данный вопрос.
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: WithRelatedBehavior

Сообщение slavcodev »

Если подсмотреть в API метода save, можно увидеть что фреймворк автоматически сделает insert для новых записей и update для старых. Поэтому insert и update редко используется по каким-то слишком частным задачам.
Жду Yii 3!
alexanoid
Сообщения: 79
Зарегистрирован: 2011.11.26, 21:48

Re: WithRelatedBehavior

Сообщение alexanoid »

mc-bear писал(а):Если подсмотреть в API метода save, можно увидеть что фреймворк автоматически сделает insert для новых записей и update для старых. Поэтому insert и update редко используется по каким-то слишком частным задачам.
а в чем была трудность реализовать базовый сценарий с удалением из базы данных отсутствующих потомков в модели при ее апдейте ? Зачем эту рутину на программиста перекладывать ? Фактически теперь приходится писать каждый раз код для этого в beforeSave..
alexanoid
Сообщения: 79
Зарегистрирован: 2011.11.26, 21:48

Re: WithRelatedBehavior

Сообщение alexanoid »

alexanoid писал(а):
mc-bear писал(а):Если подсмотреть в API метода save, можно увидеть что фреймворк автоматически сделает insert для новых записей и update для старых. Поэтому insert и update редко используется по каким-то слишком частным задачам.
а в чем была трудность реализовать базовый сценарий с удалением из базы данных отсутствующих потомков в модели при ее апдейте ? Зачем эту рутину на программиста перекладывать ? Фактически теперь приходится писать каждый раз код для этого в beforeSave..
либо в таком случае можно было добавить дополнительным параметром сценарий требуемого поведения в метод save
Аватара пользователя
XAKEPEHOK
Сообщения: 38
Зарегистрирован: 2012.08.16, 13:11
Откуда: КМВ
Контактная информация:

Re: WithRelatedBehavior

Сообщение XAKEPEHOK »

Похоже, что я где-то туплю, но не могу понять где. Есть 2 модели: Users и Advertisers, где Users HAS_ONE Advertisers, и соответственно, Advertisers BELONGS_TO Users

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

<?php
/**
 * @property integer $userID
 * ...
 * The followings are the available model relations:
 * @property Users $user
 */
class Users extends CActiveRecord
{
  //... подключаю поведение

  public function relations()
  {
    return array(
      'advertiser' => array(self::HAS_ONE, 'Advertisers', 'userID'),
    );
  }
}

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

<?php
/**
 * @property integer $id
 * ...
 * The followings are the available model relations:
 * @property Advertisers $advertiser
 */
class Advertisers extends CActiveRecord
{
  //... подключаю поведение

  public function relations()
  {
    return array(
      'user' => array(self::BELONGS_TO, 'Users', 'userID'),
    );
  }
}
В действии контроллера

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

    $user = new Users('fromRequest');
    $user->email = $advRequest->email;
    $user->login = substr($advRequest->email,0,strpos($advRequest->email,'@'));
    ...

    $user->advertiser = new Advertisers();
    $user->advertiser->name = $advRequest->name;
    $user->advertiser->phone = $advRequest->phone;    
    ...

    $user->withRelated->save(true,array('advertiser'));
В общем, при попытке сохранить получаю: Не определено свойство "Users.userID". - связи вроде указаны правильно. Ни в событиях моделей, ни в контроллере обращений к Users.userID нет.
Вылетает следующий exception:
C:\WebServer\domains\onelead\protected\extensions\wr\WithRelatedBehavior.php(239): CActiveRecord->__get("userID")

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

234         switch($relationClass)
235         {
236           case CActiveRecord::HAS_ONE:
237             $map = $this->getDependencyAttributes($fks, $ownerTableSchema, $relatedTableSchema);
238             foreach ($map as $fk => $pk) {
239               $related->$fk = $owner->$pk; // <<--- выделена эта срока
240             }
241 
242             if($data===null)
243               $related->getIsNewRecord() ? $related->insert() : $related->update();
244             else
Большинство неправильных шагов совершаются стоя на месте
Аватара пользователя
XAKEPEHOK
Сообщения: 38
Зарегистрирован: 2012.08.16, 13:11
Откуда: КМВ
Контактная информация:

Re: WithRelatedBehavior

Сообщение XAKEPEHOK »

Извиняюсь, действительно мой косяк. У меня в модели advertisers поле userID было как PRIMARY, а не как INDEX. Проблема решена
Большинство неправильных шагов совершаются стоя на месте
Adept
Сообщения: 11
Зарегистрирован: 2013.03.27, 13:41

Re: WithRelatedBehavior

Сообщение Adept »

Подскажите, как лучше всего решить ситуацию:
таблицы post, tag
связаны через posts_to_tags
tag_name - уникальный индекс
Надо чтобы при сохранении поста создавалось соответствие с тегом в таблице связей, но сами теги сохранялись только, если уникальные.
Сейчас при сохраненни тегов, мускул выдает ошибку если тег есть уже. Надо как то реализовать on duplicate key ignore для тегов.
Аватара пользователя
XAKEPEHOK
Сообщения: 38
Зарегистрирован: 2012.08.16, 13:11
Откуда: КМВ
Контактная информация:

Re: WithRelatedBehavior

Сообщение XAKEPEHOK »

Попробуйте посмотреть в сторону taggable-behavior
Большинство неправильных шагов совершаются стоя на месте
Adept
Сообщения: 11
Зарегистрирован: 2013.03.27, 13:41

Re: WithRelatedBehavior

Сообщение Adept »

Я просто думал что это расширение реализует сохранение в таблицы со связями многие к многим, а сейчас идет попытка создать дубликат в поле тег и выходит что 1 полю пост соответствует несколько тегов, но одной записы таблицы тегов соответствует 1 пост, т.е. 1 к моногим.
Adept
Сообщения: 11
Зарегистрирован: 2013.03.27, 13:41

Re: WithRelatedBehavior

Сообщение Adept »

XAKEPEHOK, спасибо! Эта штука работает как надо)
Ответить