События в yii2

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

События в yii2

Сообщение svil »

События в yii2. Нужно в таблицу event записывать факт добавления записи в таблицу article.
В дальнейшем таких таблиц будет много, откуда записывать факты создания, изменения, удаления записей.
Самая понятная статья http://qaru.site/questions/202812/how-t ... ts-in-yii2
Прочитав, мне стало ясно, что для добавления записей в таблицу event механизм событий не нужен.
Есть ли смысл создавать события, если при создании новой записи вв таблице БД также можно создавать поля в таблице Event?

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

public function actionCreate()
    {
        $model = new Article();    
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            $events = new Event();
            $events->title = "Добавлена запись: ".$model->name;
            return $this->redirect(['view', 'id' => $model->id]);
Поведение не применить, потому что поля разные в таблицах.
Аватара пользователя
Alexum
Сообщения: 683
Зарегистрирован: 2016.09.26, 10:00

Re: События в yii2

Сообщение Alexum »

Я предпочитаю записывать через afterSave(). Плюсы такого подхода: гибкость (можно фильтровать, что и как записывать в лог и хранить в сериализованном виде), сохранять новое и старое значение, записывать не id связанных элементов а их текстовые названия. Это позволяет вести журнал любых изменений с полнотекстовым поиском по изменённому значению. Минусы - под каждую модель формы нужно писать свой метод (если конечно не сделать его простым и унифицированным, но в функционале он будет уступать).

В самой простой реализации выглядит примерно так:

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

  public function afterSave($insert, $changedAttributes)
    {
        parent::afterSave($insert, $changedAttributes);
        if ($changedAttributes) {
            $log = [];
            if ($insert) {
                // Что пишем при создании записи?
            } else {
                // Что при редактировании? Н-р:	 
                foreach ($changedAttributes as $attribute => $value) {
                    $label = $this->getAttributeLabel($attribute);
                    $log[$label] = [
                        0 => $value, // Старое значение
                        1 => $this->$attribute, // Новое значение
                    ];
                }
            }
            Log::record($this->id, self::tableName(), serialize($log), $this->getScenario());
        }
    }
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

Есть таблица Article и другие таблицы в БД, при добавлении в них записи
должна заполняться таблица Event.
Пока не выходит

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

<?php
namespace app\components;

use yii\base\Application;
use yii\base\BootstrapInterface;
use yii\base\Event;
use yii\db\ActiveRecord;

class ShopNotificator implements BootstrapInterface
{


    /**
     * Bootstrap method to be called during application bootstrap stage.
     * @param Application $app the application currently running
     */
    public function bootstrap($app)
    {


        Event::on(
            ActiveRecord::className(),
            ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
            [$this, 'opinionCreated'];
        });


    }
    public function opinionCreated(Event $event)
    {
        $ev = new  \app\models\Event();
        $ev->title = $event->sender;
        $ev->save();

    }
}
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: События в yii2

Сообщение ElisDN »

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

'bootstrap' => [
    'log',
    ShopNotificator::class,
]
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

Спасибо
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

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

Unknown bootstrapping component ID: ShopNotificator
Добавила

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

 'components' => [
        'ShopNotificator' => [
                 'class' => 'app\components\ShopNotificator'],
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

Не помогло, запись в таблицу \app\models\Event() не добавляется
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: События в yii2

Сообщение ElisDN »

А что в $ev->title присваиваете?
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

Пока так пробую для теста

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

$ev->title = "текстовочка";
           
Когда запишется, хочу получать данные из $event, нужны поля таблиц, данные в которые добавляются/редактируются
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: События в yii2

Сообщение yiiliveext »

svil писал(а): 2019.08.12, 21:02 Есть таблица Article и другие таблицы в БД, при добавлении в них записи
должна заполняться таблица Event.
Пока не выходит

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

<?php

    public function bootstrap($app)
    {


        Event::on(
            ActiveRecord::className(),
            ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
            [$this, 'opinionCreated'];
        });


    }
   
}
У вас функция ничего не возвращает.

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

 public function bootstrap($app)
    {


        Event::on(
            ActiveRecord::className(),
            ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
            return [$this, 'opinionCreated'];
        });


    }
P.S. Посмотрел исходники Yii, так все равно работать не будет. Смотрите ответ ниже.
Последний раз редактировалось yiiliveext 2019.08.13, 11:41, всего редактировалось 1 раз.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: События в yii2

Сообщение yiiliveext »

svil писал(а): 2019.08.12, 21:02

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

<?php
        Event::on(
            ActiveRecord::className(),
            ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
            [$this, 'opinionCreated'];
        });


Вот так вот будет работать.

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


        Event::on(
            ActiveRecord::className(),
            ActiveRecord::EVENT_AFTER_INSERT,
             [$this, 'opinionCreated']
            );
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

Процесс сдвинулся стремительно с мертвой точки и вставил в таблицу event 2873 записей одинаковых "тестирую событие" на локальном
и выдает ошибку
PHP Fatal Error – yii\base\ErrorException

Maximum execution time of 30 seconds exceeded

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

1. in /Users/svetlanailina/Sites/yii2_bz_events/vendor/yiisoft/yii2/log/Logger.php at line 148
139140141142143144145146147148149150151152153154155156157     * `Logger::LEVEL_PROFILE_BEGIN`, `Logger::LEVEL_PROFILE_END`.
     * @param string $category the category of the message.
     */
    public function log($message, $level, $category = 'application')
    {
        $time = microtime(true);
        $traces = [];
        if ($this->traceLevel > 0) {
            $count = 0;
            $ts = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
            array_pop($ts); // remove the last trace since it would be the entry script, not very useful
            foreach ($ts as $trace) {
                if (isset($trace['file'], $trace['line']) && strpos($trace['file'], YII2_PATH) !== 0) {
                    unset($trace['object'], $trace['args']);
                    $traces[] = $trace;
                    if (++$count >= $this->traceLevel) {
                        break;
                    }
                }
2. yii\base\ErrorHandler::handleFatalError()
$_POST = [
    '_csrf' => 'PGufsxVqqLB214SdLf3-7uEWoM6Utm5kcUPz824fPaFIKdjDUi2f3wG27fR-m7LevmLrlNrfPi4_Mb2KFil85A==',
    'Article' => [
        'name' => 'оо',
        'description' => 'оо',
    ],
];

$_COOKIE = [
    'PHPSESSID' => 'mih734mjfnn2h3khqjepdc2101',
    '_csrf' => '8946c09f1e67ae68c3ae223e81a87a3a17d9ce56304208c71d1424e9ab5bb87ca:2:{i:0;s:5:"_csrf";i:1;s:32:"tBGpGG7owaiiSfL0_tKZNiPJNrNyx6AE";}',
    'advanced' => 'uva7rlvbdk3ckqnfhabav4f0in',
    '_csrf-frontend' => 'f6a02f99fc6fa0922c68d462510876e80094e5ecf7931ef4406a4d89a49cc25fa:2:{i:0;s:14:"_csrf-frontend";i:1;s:32:"jkSfkPcGSh_vMGDfRI5RdLL_B7Bs9tUr";}',
];

$_SESSION = [
    '__flash' => [],
];
Yii Framework
2019-08-13, 18:51:06

Apache/2.4.37 (Unix) PHP/7.1.24
https://github.com/svil1502/yii2_bz_events
На удаленном хостинге выдает 502 ошибку
web.php

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

<?php

$params = require __DIR__ . '/params.php';
$db = require __DIR__ . '/db.php';

$config = [
    'id' => 'basic',
    'basePath' => dirname(__DIR__),
    'bootstrap' => [
        'log',
        ShopNotificator::class,
    ],
    'aliases' => [
        '@bower' => '@vendor/bower-asset',
        '@npm'   => '@vendor/npm-asset',
    ],
    'components' => [
        'ShopNotificator' => [
                 'class' => 'app\components\ShopNotificator'],
        'request' => [
            // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
            'cookieValidationKey' => 'tATR8OV7ELA9FeQYX3fCDoKk_tmG6Egn',
        ],

        'cache' => [
            'class' => 'yii\caching\FileCache',
        ],
        'user' => [
            'identityClass' => 'app\models\User',
            'enableAutoLogin' => true,
        ],
        'errorHandler' => [
            'errorAction' => 'site/error',
        ],
        'mailer' => [
            'class' => 'yii\swiftmailer\Mailer',
            // send all mails to a file by default. You have to set
            // 'useFileTransport' to false and configure a transport
            // for the mailer to send real emails.
            //'useFileTransport' => true,
            'useFileTransport' => false,
        ],
        'log' => [
            'traceLevel' => YII_DEBUG ? 3 : 0,
            'targets' => [
                [
                    'class' => 'yii\log\FileTarget',
                    'levels' => ['error', 'warning'],
                ],
            ],
        ],
        'db' => $db,

        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'rules' => [
            ],
        ],

    ],
    'params' => $params,
];

if (YII_ENV_DEV) {
    // configuration adjustments for 'dev' environment
    $config['bootstrap'][] = 'debug';
    $config['modules']['debug'] = [
        'class' => 'yii\debug\Module',
        // uncomment the following to add your IP if you are not connecting from localhost.
        //'allowedIPs' => ['127.0.0.1', '::1'],
    ];

    $config['bootstrap'][] = 'gii';
    $config['modules']['gii'] = [
        'class' => 'yii\gii\Module',
        // uncomment the following to add your IP if you are not connecting from localhost.
        //'allowedIPs' => ['127.0.0.1', '::1'],
    ];
}

return $config;
components/

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

<?php
namespace app\components;

use yii\base\Application;
use yii\base\BootstrapInterface;
use yii\base\Event;
use yii\db\ActiveRecord;

class ShopNotificator implements BootstrapInterface
{


    /**
     * Bootstrap method to be called during application bootstrap stage.
     * @param Application $app the application currently running
     */
    public function bootstrap($app)
    {


//        Event::on(
//            ActiveRecord::className(),
//            ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
//            [$this, 'opinionCreated'];
//        });

        Event::on(
            ActiveRecord::className(),
            ActiveRecord::EVENT_AFTER_INSERT,
            [$this, 'opinionCreated']
        );

//        Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
//            Yii::debug(get_class($event->sender) . ' добавлен');
//            $ev = new  \app\models\Event();
//            $ev->title = "текстовочка";
//            //$event->sender;
//            $ev->save();
//        });


    }
    public function opinionCreated(Event $event)
    {
        $ev = new  \app\models\Event();
        $ev->title = "тестирую событие";
            //$event->sender;
        $ev->save();

    }
}
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: События в yii2

Сообщение yiiliveext »

Вы можете установить set_time_limit (0), но если у вас запрос не укладывается в 30 секунд, то вам скорее нужно пересмотреть архитектуру приложения.
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

А почему вставляется 2873 записей в таблицу Event?
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

Я добавляю в таблицу Article 1 запись, после которой вставляется в таблицу Event 2873 записей с title "тестирую событие"
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

Архитектура для теста взята basic, две таблицы и больше ничего
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: События в yii2

Сообщение ElisDN »

svil писал(а): 2019.08.13, 22:24 Я добавляю в таблицу Article 1 запись, после которой вставляется в таблицу Event 2873 записей с title "тестирую событие"
Потому что $ev->save() тоже генерирует событие и скрипт зацикливается.

Вставляйте через Yii::$app->db->createCommand()->insert('events', ['title' => ...])->execute().
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

Вместо даты created_at вставился null
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

Модель event

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

<?php

namespace app\models;

use Yii;
use yii\behaviors\TimestampBehavior;


/**
 * This is the model class for table "event".
 *
 * @property int $id
 * @property string $title
 */
class Event extends \yii\db\ActiveRecord
{
    public function behaviors()
    {
        return [
            TimestampBehavior::className(),
        ];
    }

    /**
     * {@inheritdoc}
     */
    public static function tableName()
    {
        return 'event';
    }

    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
           // [['title'], 'required'],
            [['title'], 'string', 'max' => 250],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'title' => 'Title',
        ];
    }
}
Аватара пользователя
svil
Сообщения: 563
Зарегистрирован: 2018.02.12, 22:41

Re: События в yii2

Сообщение svil »

В модел event дату настроить? Потому что при save() дату добавляло текущую через TimestampBehavior::className()
Ответить