Spec-Zone.ru › Phalcon 3

События модели

События и менеджер событий

Модели позволяют вам реализовать события, которые будут срабатывать во время выполнения операций вставки/обновления/удаления, что может быть использовано для определения бизнес-правил. Ниже приведены поддерживаемые события Phalcon\Mvc\Model и их порядок выполнения:

Операция Имя Можно остановить операцию? Описание
Вставка/Обновление beforeValidation ДА Выполняется перед валидацией полей на предмет отсутствия значений NULL/пустых строк или внешних ключей
Вставка beforeValidationOnCreate ДА Выполняется перед валидацией полей на предмет отсутствия значений NULL/пустых строк или внешних ключей при выполнении операции вставки
Обновление beforeValidationOnUpdate ДА Выполняется перед валидацией полей на предмет отсутствия значений NULL/пустых строк или внешних ключей при выполнении операции обновления
Вставка/Обновление onValidationFails ДА (уже остановлено) Выполняется после того, как валидатор целостности завершил работу с ошибкой
Вставка afterValidationOnCreate ДА Выполняется после валидации полей на предмет отсутствия значений NULL/пустых строк или внешних ключей при выполнении операции вставки
Обновление afterValidationOnUpdate ДА Выполняется после валидации полей на предмет отсутствия значений NULL/пустых строк или внешних ключей при выполнении операции обновления
Вставка/Обновление afterValidation ДА Выполняется после валидации полей на предмет отсутствия значений NULL/пустых строк или внешних ключей
Вставка/Обновление beforeSave ДА Выполняется перед необходимой операцией над системой базы данных
Обновление beforeUpdate ДА Выполняется перед необходимой операцией над системой базы данных только при выполнении операции обновления
Вставка beforeCreate ДА Выполняется перед необходимой операцией над системой базы данных только при выполнении операции вставки
Обновление afterUpdate НЕТ Выполняется после необходимой операции над системой базы данных только при выполнении операции обновления
Вставка afterCreate НЕТ Выполняется после необходимой операции над системой базы данных только при выполнении операции вставки
Вставка/Обновление afterSave НЕТ Выполняется после необходимой операции над системой базы данных

Реализация событий в классе модели

Проще всего заставить модель реагировать на события, реализовав метод с тем же именем, что и событие, в классе модели:

namespace Store\Toys;

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public function beforeValidationOnCreate()
    {
        echo "This is executed before creating a Robot!";
    }
}

События могут использоваться для присвоения значений перед выполнением операции, например:

use Phalcon\Mvc\Model;

class Products extends Model
{
    public function beforeCreate()
    {
        // Set the creation date
        $this->created_at = date("Y-m-d H:i:s");
    }

    public function beforeUpdate()
    {
        // Set the modification date
        $this->modified_in = date("Y-m-d H:i:s");
    }
}

Использование пользовательского менеджера событий

Кроме того, этот компонент интегрирован с Phalcon\Events\Manager, что означает, что мы можем создавать слушателей, которые запускаются при срабатывании события.

namespace Store\Toys;

use Phalcon\Mvc\Model;
use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;

class Robots extends Model
{
    public function initialize()
    {
        $eventsManager = new EventsManager();

        // Attach an anonymous function as a listener for "model" events
        $eventsManager->attach(
            "model:beforeSave",
            function (Event $event, $robot) {
                if ($robot->name === "Scooby Doo") {
                    echo "Scooby Doo isn't a robot!";

                    return false;
                }

                return true;
            }
        );

        // Attach the events manager to the event
        $this->setEventsManager($eventsManager);
    }
}

В приведенном выше примере менеджер событий только действует как посредник между объектом и слушателем (анонимной функцией). События будут отправляться слушателю при сохранении «роботов»:

use Store\Toys\Robots;

$robot = new Robots();

$robot->name = "Scooby Doo";
$robot->year = 1969;

$robot->save();

Если мы хотим, чтобы все созданные объекты в нашем приложении использовали один и тот же EventsManager, то нам нужно назначить его менеджеру моделей:

use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;

// Registering the modelsManager service
$di->setShared(
    "modelsManager",
    function () {
        $eventsManager = new EventsManager();

        // Attach an anonymous function as a listener for "model" events
        $eventsManager->attach(
            "model:beforeSave",
            function (Event $event, $model) {
                // Catch events produced by the Robots model
                if (get_class($model) === "Store\\Toys\\Robots") {
                    if ($model->name === "Scooby Doo") {
                        echo "Scooby Doo isn't a robot!";

                        return false;
                    }
                }

                return true;
            }
        );

        // Setting a default EventsManager
        $modelsManager = new ModelsManager();

        $modelsManager->setEventsManager($eventsManager);

        return $modelsManager;
    }
);

Если слушатель возвращает false, это остановит выполняющуюся операцию.

Ведение журнала низкоуровневых SQL-запросов

При использовании высокоуровневых абстрактных компонентов, таких как Phalcon\Mvc\Model для доступа к базе данных, трудно понять, какие запросы в конечном итоге отправляются в систему базы данных. Phalcon\Mvc\Model поддерживается внутри Phalcon\Db. Phalcon\Logger взаимодействует с Phalcon\Db, обеспечивая возможности ведения журнала на уровне абстракции базы данных, что позволяет нам записывать SQL-запросы по мере их выполнения.

use Phalcon\Logger;
use Phalcon\Events\Manager;
use Phalcon\Logger\Adapter\File as FileLogger;
use Phalcon\Db\Adapter\Pdo\Mysql as Connection;

$di->set(
    "db",
    function () {
        $eventsManager = new EventsManager();

        $logger = new FileLogger("app/logs/debug.log");

        // Listen all the database events
        $eventsManager->attach(
            "db:beforeQuery",
            function ($event, $connection) use ($logger) {
                $logger->log(
                    $connection->getSQLStatement(),
                    Logger::INFO
                );
            }
        );

        $connection = new Connection(
            [
                "host"     => "localhost",
                "username" => "root",
                "password" => "secret",
                "dbname"   => "invo",
            ]
        );

        // Assign the eventsManager to the db adapter instance
        $connection->setEventsManager($eventsManager);

        return $connection;
    }
);

Поскольку модели обращаются к подключению к базе данных по умолчанию, все SQL-запросы, которые отправляются в систему базы данных, будут записываться в файл:

use Store\Toys\Robots;

$robot = new Robots();

$robot->name       = "Robby the Robot";
$robot->created_at = "1956-07-21";

if ($robot->save() === false) {
    echo "Cannot save robot";
}

Как и выше, файл app/logs/db.log будет содержать что-то вроде этого:

[Mon, 30 Apr 12 13:47:18 -0500][DEBUG][Resource Id #77] INSERT INTO robots
(name, created_at) VALUES ('Robby the Robot', '1956-07-21')

Профилирование SQL-запросов

Благодаря Phalcon\Db, базовому компоненту Phalcon\Mvc\Model, можно профилировать SQL-запросы, генерируемые ORM, чтобы проанализировать производительность операций с базой данных. С помощью этого вы можете диагностировать проблемы производительности и найти узкие места.

use Phalcon\Db\Profiler as ProfilerDb;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Db\Adapter\Pdo\Mysql as MysqlPdo;

$di->set(
    "profiler",
    function () {
        return new ProfilerDb();
    },
    true
);

$di->set(
    "db",
    function () use ($di) {
        $eventsManager = new EventsManager();

        // Get a shared instance of the DbProfiler
        $profiler = $di->getProfiler();

        // Listen all the database events
        $eventsManager->attach(
            "db",
            function ($event, $connection) use ($profiler) {
                if ($event->getType() === "beforeQuery") {
                    $profiler->startProfile(
                        $connection->getSQLStatement()
                    );
                }

                if ($event->getType() === "afterQuery") {
                    $profiler->stopProfile();
                }
            }
        );

        $connection = new MysqlPdo(
            [
                "host"     => "localhost",
                "username" => "root",
                "password" => "secret",
                "dbname"   => "invo",
            ]
        );

        // Assign the eventsManager to the db adapter instance
        $connection->setEventsManager($eventsManager);

        return $connection;
    }
);

Профилирование некоторых запросов:

use Store\Toys\Robots;

// Send some SQL statements to the database
Robots::find();

Robots::find(
    [
        "order" => "name",
    ]
);

Robots::find(
    [
        "limit" => 30,
    ]
);

// Get the generated profiles from the profiler
$profiles = $di->get("profiler")->getProfiles();

foreach ($profiles as $profile) {
   echo "SQL Statement: ", $profile->getSQLStatement(), "\n";
   echo "Start Time: ", $profile->getInitialTime(), "\n";
   echo "Final Time: ", $profile->getFinalTime(), "\n";
   echo "Total Elapsed Time: ", $profile->getTotalElapsedSeconds(), "\n";
}

Каждый сгенерированный профиль содержит время в миллисекундах, которое требуется для выполнения каждой инструкции, а также сгенерированный SQL-запрос.

© 2011–2017 Phalcon Framework Team
Licensed under the Creative Commons Attribution License 3.0.
https://docs.phalconphp.com/en/latest/reference/model-events.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API