Не могу разобратся с ивентами

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
fly2k
Сообщения: 155
Зарегистрирован: 2013.03.19, 05:31

Re: Не могу разобратся с ивентами

Сообщение fly2k »

Вы сами пробовали делать условие по scenario в behaviors? как я и подозревал, этому методу сильно пофигу на то как меняется сценарий после создания модели... я пробовал два варианта:

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

...
$this->_user = User::findByLogin($this->login);
$this->_user->scenario = 'login'; // вариант 1
Yii::configure($this->_user, ['scenario' => 'login']); // вариант 2
...
я пока не разобрался где и как дёргается behavoirs(), но на момент его вызова scenario = 'default'...
на момент вызова save() - конечно уже 'login', это точно, сценарий тут установлен ок, пробовал устанавливать несуществующий сценарий - получил исключение (я уже все возможные тупняки пытаюсь исключить :) ).
как передать сценарий в findByLogin/findOne/и тд - для меня чего то не очевидно...
так что вот...

весь код такой:
LoginForm.php:

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

...
    public function login()
    {
        if ($this->validate() && $this->user) {
            $return = Yii::$app->user->login($this->_user, $this->rememberMe ? 3600 * 24 * 30 : 0);
            if($return) {
                $this->_user->trigger(User::EVENT_LOGIN);
                $this->_user->save();
            }
            return $return;
        } else {
            return false;
        }
    }

    public function getUser()
    {
        if ($this->_user === false) {
            $this->_user = User::findByLogin($this->login);
            Yii::configure($this->_user, ['scenario' => 'login']);
        }
        return $this->_user;
    }

}
...
 
User.php:

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

...
    const EVENT_LOGIN = 'user_login';
    public function behaviors()
    {

        $timestampAttributes = [];
        if($this->scenario == 'login') {
            $timestampAttributes[self::EVENT_LOGIN] = ['logged_at'];
        } else {
            $timestampAttributes[self::EVENT_BEFORE_INSERT] = ['created_at', 'updated_at'];
            $timestampAttributes[self::EVENT_BEFORE_UPDATE] = ['updated_at'];
        }

        return array_merge(parent::behaviors(),
            [
                'timestamp' => [
                    'class' => TimestampBehavior::className(),
                    'attributes' => $timestampAttributes,
                ],
            ]
        );
    }
...
 
что я делаю не так?
// Yii2Rulez!
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Не могу разобратся с ивентами

Сообщение zelenin »

да, когда я писал, думал о том, что возможно сценарий при загрузке поведений еще default. Сейчас сказать нчиего не могу - нет под рукой yii2.
Аватара пользователя
yiijeka
Сообщения: 3103
Зарегистрирован: 2012.01.28, 09:14
Откуда: Беларусь
Контактная информация:

Re: Не могу разобратся с ивентами

Сообщение yiijeka »

Не ?

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

$user = new User;
$user->scenario = 'login';
$this->_user = $user::findByLogin($this->login);
Последний раз редактировалось yiijeka 2014.09.16, 16:07, всего редактировалось 1 раз.
fly2k
Сообщения: 155
Зарегистрирован: 2013.03.19, 05:31

Re: Не могу разобратся с ивентами

Сообщение fly2k »

yiijeka писал(а):Не ?

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

$user = new User;
$user->scenario = 'login';
$this->_user = user::findByLogin($this->login);
не очень понял. В последней строке User или $user ?
В первом случае, получается $user(и его scenario) ни на что не влияет. Во втором случае - можно ли вызывать статический метод из экземпляра класса и что из этого выйдет?

Вообще, конечно, у меня сложилось впечатление, что это всё как то из области хаков-костылей, типа сценарии для валидации задумывались и баста... да и принципиально именно вот loagged_at обновлять, наверное, всё таки проще чуть ли не прямым SQL, не шевеля ничего больше, не создавая поведений, событий и тд... да и красивость такого решения(поведение/событие/сценарий) не так уж велика когда видишь в коде обработки логина вызов $user->save(), которому там по логике нечего делать...

Но вот хотелось бы разобраться, докопаться до сути и обрести всё таки понимание... а то у людей куча вариантов, а у меня одни загвоздки ;)
// Yii2Rulez!
Аватара пользователя
yiijeka
Сообщения: 3103
Зарегистрирован: 2012.01.28, 09:14
Откуда: Беларусь
Контактная информация:

Re: Не могу разобратся с ивентами

Сообщение yiijeka »

Поправил. Чёрт и я опечатался.
Аватара пользователя
yiijeka
Сообщения: 3103
Зарегистрирован: 2012.01.28, 09:14
Откуда: Беларусь
Контактная информация:

Re: Не могу разобратся с ивентами

Сообщение yiijeka »

По правильному если вам нужно что-то после аутентификации, то вам сюда - https://github.com/yiisoft/yii2/blob/09 ... er.php#L62
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Не могу разобратся с ивентами

Сообщение zelenin »

добавь к моему коду
$scenarios = $this->scenarios();
$scenario = $this->getScenario();
fly2k
Сообщения: 155
Зарегистрирован: 2013.03.19, 05:31

Re: Не могу разобратся с ивентами

Сообщение fly2k »

$user::findByLogin($this->login); сработал, и даже не сругалось, но я думаю, что это тоже самое что и обычный вызов User::findByLogin($this->login); ибо сама эта функция статическая и не может быть привязана ни к какому объекту... внутри неё все равно создается новый обект, уже с помощью тоже статичесакой findOne()...
в общем не канает...
// Yii2Rulez!
fly2k
Сообщения: 155
Зарегистрирован: 2013.03.19, 05:31

Re: Не могу разобратся с ивентами

Сообщение fly2k »

zelenin писал(а):добавь к моему коду
$scenarios = $this->scenarios();
$scenario = $this->getScenario();
вот щас ваще не понил :о
это в behsviors() добавить? смысла не могу уловить...
// Yii2Rulez!
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Не могу разобратся с ивентами

Сообщение zelenin »

хотя нет. по идее сценарий сразу должен быть не дефолт.
fly2k
Сообщения: 155
Зарегистрирован: 2013.03.19, 05:31

Re: Не могу разобратся с ивентами

Сообщение fly2k »

yiijeka писал(а):По правильному если вам нужно что-то после аутентификации, то вам сюда - https://github.com/yiisoft/yii2/blob/09 ... er.php#L62
ну да, прикольно, событие можно своё не придумывать, а вешать на EVENT_AFTER_LOGIN, но трабла остается - как при этом не цеплять updated_at?
вообще конкретно по этой проблеме - пофигу, как я уже писал... но вот вообще поиметь возможность менять поведения в зависимости от сценария - оно было бы круто все таки... так что пилим дальше :)

может быть вызвать какой то метод "переинициализации" поведений(такой вообще есть?) после смены сценария... кто и как вообще дергает behaviors()? нужно просто сделать тоже самое :) тока я найти не знаю как...
// Yii2Rulez!
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Не могу разобратся с ивентами

Сообщение zelenin »

сценарий назначается до init, так что у вас видимо где-то ошибка
fly2k
Сообщения: 155
Зарегистрирован: 2013.03.19, 05:31

Re: Не могу разобратся с ивентами

Сообщение fly2k »

zelenin писал(а):хотя нет. по идее сценарий сразу должен быть не дефолт.
ну или после смены сценария как то "перевызвать" behaviors()

мне вот интересно, что по этому поводу разрабы думают? а то как скажут, типа, вы ваще тут долбанулись, так оно не задумывалось, и нефик мучаться...
потому что, ведь если бы задумывалось, не проблема была бы "перевызвать" behaviors() в setScenario() или еще как то предусмотреть. Дефолтный сценарий, тоже удивительно что не понятно как задать... то есть в функциях, которые возвращают модель, типа findOne() нет возможности указать сценарий, или какие то другие свойства будущего экземпляра.
// Yii2Rulez!
fly2k
Сообщения: 155
Зарегистрирован: 2013.03.19, 05:31

Re: Не могу разобратся с ивентами

Сообщение fly2k »

zelenin писал(а):сценарий назначается до init, так что у вас видимо где-то ошибка
опять не понял. о каком init идет речь? вот же ж:

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

$this->_user = User::findByLogin($this->login); // findByLogin => findOne => query... то есть нигде нет возможности задать сценарий. 
// $this->_user>scenario равен 'default', behaviors() уже отработал
$this->_user->scenario = 'login'; // вариант 1
Yii::configure($this->_user, ['scenario' => 'login']); // вариант 2
// $this->_user->scenario равен 'login', но не пофиг на это только $this->_user->save()
// Yii2Rulez!
fly2k
Сообщения: 155
Зарегистрирован: 2013.03.19, 05:31

Re: Не могу разобратся с ивентами

Сообщение fly2k »

как то так:

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

...
$this->_user = User::findByLogin($this->login);
Yii::configure($this->_user, ['scenario' => 'login']);
$this->_user->detachBehaviors();
$this->_user->attachBehaviors($this->_user->behaviors());
...
 
всё работает как нада...

ну и вообще было полезно почитать Component.php :) эти бихэверы можно ваще вертеть как хочешь в рантайме, и совершенно не обязательно зацикливаться на методе behaviors() :)
// Yii2Rulez!
Аватара пользователя
yiijeka
Сообщения: 3103
Зарегистрирован: 2012.01.28, 09:14
Откуда: Беларусь
Контактная информация:

Re: Не могу разобратся с ивентами

Сообщение yiijeka »

->on(...) мне больше нравится. Попробуйте его ещё покрутить.
Аватара пользователя
yiijeka
Сообщения: 3103
Зарегистрирован: 2012.01.28, 09:14
Откуда: Беларусь
Контактная информация:

Re: Не могу разобратся с ивентами

Сообщение yiijeka »

Например вот так, добавив одну строку кода в модели LoginForm, обновляем поле в бд, при успешной аутентификации пользователя.

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

    public function login()
    {
        if ($this->validate()) {
            Yii::$app->user->on(UserComponent::EVENT_AFTER_LOGIN, function ($event) {$event->identity->touch('updated_at');});
            return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
        } else {
            return false;
        }
    }
UserComponent это "use yii\web\User as UserComponent;"
fly2k
Сообщения: 155
Зарегистрирован: 2013.03.19, 05:31

Re: Не могу разобратся с ивентами

Сообщение fly2k »

yiijeka писал(а):Например вот так, добавив одну строку кода в модели LoginForm, обновляем поле в бд, при успешной аутентификации пользователя.

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

    public function login()
    {
        if ($this->validate()) {
            Yii::$app->user->on(UserComponent::EVENT_AFTER_LOGIN, function ($event) {$event->identity->touch('updated_at');});
            return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
        } else {
            return false;
        }
    }
UserComponent это "use yii\web\User as UserComponent;"
хз, я не очень догнал... но много нового узнал, опять же спасибо :)
пока сделал так:

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

    public function login()
    {
        if ($this->validate() && $this->user) {
            $return = Yii::$app->user->login($this->_user, $this->rememberMe ? 3600 * 24 * 30 : 0);
            if($return) {
                $this->_user->touch('logged_at');
                $this->_user->save();
            }
            return $return;
        } else {
            return false;
        }
    }
при этом всё равно нада следить чтобы остальный поля(updated_at) не трогались, то есть поведения должны быть разными при разных сценариях(login или update)
// Yii2Rulez!
Аватара пользователя
yiijeka
Сообщения: 3103
Зарегистрирован: 2012.01.28, 09:14
Откуда: Беларусь
Контактная информация:

Re: Не могу разобратся с ивентами

Сообщение yiijeka »

Из моего кода выше,
on присоединяет функцию обработчик( function ($event) { ... }) к компоненту yii\web\User as UserComponent, этот обработчик сработает при срабатывании события UserComponent::EVENT_AFTER_LOGIN .А это событие срабатывает только после успешного входа пользователя - аутентификации.

И в твоём коде save() лишнее. Так как touch уже послал на сохранение одно поле.
Ответить