Менеджер событий
Цель данного компонента — перехватить выполнение большинства компонентов фреймворка, создавая «точки подключения». Эти точки подключения позволяют разработчику получить информацию о статусе, манипулировать данными или изменять поток выполнения во время работы компонента.
Пример использования
В следующем примере мы используем EventsManager для прослушивания событий, генерируемых в подключении к MySQL, управляемом Phalcon\Db. Сначала нам нужен объект-прослушиватель для этого. Мы создали класс, методы которого являются событиями, которые мы хотим прослушивать:
class MyDbListener
{
public function afterConnect()
{
}
public function beforeQuery()
{
}
public function afterQuery()
{
}
}
Этот новый класс может быть столь подробным, насколько нам это нужно. EventsManager будет выступать в качестве посредника между компонентом и нашим классом-прослушивателем, предоставляя точки подключения на основе методов, определенных в нашем классе-прослушивателе:
use Phalcon\Events\Manager as EventsManager,
Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
$eventsManager = new EventsManager();
//Create a database listener
$dbListener = new MyDbListener();
//Listen all the database events
$eventsManager->attach('db', $dbListener);
$connection = new DbAdapter(array(
"host" => "localhost",
"username" => "root",
"password" => "secret",
"dbname" => "invo"
));
//Assign the eventsManager to the db adapter instance
$connection->setEventsManager($eventsManager);
//Send a SQL command to the database server
$connection->query("SELECT * FROM products p WHERE p.status = 1");
Для того, чтобы регистрировать все SQL-запросы, выполняемые нашим приложением, нам нужно использовать событие «afterQuery». Первый параметр, передаваемый в прослушиватель событий, содержит контекстную информацию о выполняемом событии, второй — само подключение.
use Phalcon\Logger\Adapter\File as Logger;
class MyDbListener
{
protected $_logger;
public function __construct()
{
$this->_logger = new Logger("../apps/logs/db.log");
}
public function afterQuery($event, $connection)
{
$this->_logger->log($connection->getSQLStatement(), \Phalcon\Logger::INFO);
}
}
В рамках этого примера мы также реализуем Phalcon\Db\Profiler для определения SQL-запросов, которые занимают больше времени, чем ожидалось:
use Phalcon\Db\Profiler,
Phalcon\Logger,
Phalcon\Logger\Adapter\File;
class MyDbListener
{
protected $_profiler;
protected $_logger;
/**
* Creates the profiler and starts the logging
*/
public function __construct()
{
$this->_profiler = new Profiler();
$this->_logger = new Logger("../apps/logs/db.log");
}
/**
* This is executed if the event triggered is 'beforeQuery'
*/
public function beforeQuery($event, $connection)
{
$this->_profiler->startProfile($connection->getSQLStatement());
}
/**
* This is executed if the event triggered is 'afterQuery'
*/
public function afterQuery($event, $connection)
{
$this->_logger->log($connection->getSQLStatement(), Logger::INFO);
$this->_profiler->stopProfile();
}
public function getProfiler()
{
return $this->_profiler;
}
}
Результирующие данные профиля можно получить из прослушивателя:
//Send a SQL command to the database server
$connection->execute("SELECT * FROM products p WHERE p.status = 1");
foreach ($dbListener->getProfiler()->getProfiles() 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";
}
Аналогичным образом мы можем зарегистрировать лямбда-функцию для выполнения задачи вместо отдельного класса-прослушивателя (как показано выше):
//Listen all the database events
$eventManager->attach('db', function($event, $connection) {
if ($event->getType() == 'afterQuery') {
echo $connection->getSQLStatement();
}
});
Создание компонентов, генерирующих события
Вы можете создавать компоненты в своем приложении, которые генерируют события для EventsManager. В результате могут существовать прослушиватели, реагирующие на эти события при их возникновении. В следующем примере мы создаем компонент под названием «MyComponent». Этот компонент поддерживает EventsManager; при выполнении его метода «someTask» он генерирует два события для любого прослушивателя в EventsManager:
use Phalcon\Events\EventsAwareInterface;
class MyComponent implements EventsAwareInterface
{
protected $_eventsManager;
public function setEventsManager($eventsManager)
{
$this->_eventsManager = $eventsManager;
}
public function getEventsManager()
{
return $this->_eventsManager;
}
public function someTask()
{
$this->_eventsManager->fire("my-component:beforeSomeTask", $this);
// do some task
$this->_eventsManager->fire("my-component:afterSomeTask", $this);
}
}
Обратите внимание, что события, генерируемые этим компонентом, имеют префикс «my-component». Это уникальное слово, которое помогает нам идентифицировать события, генерируемые определенным компонентом. Вы даже можете генерировать события вне компонента с тем же именем. Теперь давайте создадим прослушиватель для этого компонента:
class SomeListener
{
public function beforeSomeTask($event, $myComponent)
{
echo "Here, beforeSomeTask\n";
}
public function afterSomeTask($event, $myComponent)
{
echo "Here, afterSomeTask\n";
}
}
Прослушиватель — это просто класс, который реализует любое из всех событий, генерируемых компонентом. Теперь давайте заставим всё работать вместе:
//Create an Events Manager
$eventsManager = new Phalcon\Events\Manager();
//Create the MyComponent instance
$myComponent = new MyComponent();
//Bind the eventsManager to the instance
$myComponent->setEventsManager($eventsManager);
//Attach the listener to the EventsManager
$eventsManager->attach('my-component', new SomeListener());
//Execute methods in the component
$myComponent->someTask();
При выполнении «someTask» два метода в прослушивателе будут выполнены, что приведет к следующему выводу:
Here, beforeSomeTask Here, afterSomeTask
Дополнительные данные также могут быть переданы при генерировании события с помощью третьего параметра «fire»:
$eventsManager->fire("my-component:afterSomeTask", $this, $extraData);
В прослушивателе третий параметр также получает эти данные:
//Receiving the data in the third parameter
$eventManager->attach('my-component', function($event, $component, $data) {
print_r($data);
});
//Receiving the data from the event context
$eventManager->attach('my-component', function($event, $component) {
print_r($event->getData());
});
Если прослушиватель интересуется только прослушиванием определенного типа события, вы можете прикрепить прослушиватель непосредственно:
//The handler will only be executed if the event triggered is "beforeSomeTask"
$eventManager->attach('my-component:beforeSomeTask', function($event, $component) {
//...
});
Распространение/отмена события
Может быть добавлено много прослушивателей к одному менеджеру событий, это означает, что для одного и того же типа события может быть уведомлено множество прослушивателей. Прослушиватели уведомляются в порядке их регистрации в EventsManager. Некоторые события могут быть отменены, что означает, что они могут быть остановлены, предотвращая уведомление других прослушивателей о событии:
$eventsManager->attach('db', function($event, $connection){
//We stop the event if it is cancelable
if ($event->isCancelable()) {
//Stop the event, so other listeners will not be notified about this
$event->stop();
}
//...
});
По умолчанию события могут быть отменены, даже большинство событий, генерируемых фреймворком, являются отменяемыми. Вы можете сгенерировать неотменяемое событие, передав «false» в четвертом параметре fire:
$eventsManager->fire("my-component:afterSomeTask", $this, $extraData, false);
Приоритеты прослушивателей
При добавлении прослушивателей вы можете установить определённый приоритет. С помощью этой функции вы можете добавить прослушиватели, указывая порядок их вызова:
$evManager->enablePriorities(true);
$evManager->attach('db', new DbListener(), 150); //More priority
$evManager->attach('db', new DbListener(), 100); //Normal priority
$evManager->attach('db', new DbListener(), 50); //Less priority
Сбор ответов
Менеджер событий может собирать каждый ответ, возвращаемый каждым уведомлённым прослушивателем, этот пример объясняет, как это работает:
use Phalcon\Events\Manager as EventsManager;
$evManager = new EventsManager();
//Set up the events manager to collect responses
$evManager->collectResponses(true);
//Attach a listener
$evManager->attach('custom:custom', function() {
return 'first response';
});
//Attach a listener
$evManager->attach('custom:custom', function() {
return 'second response';
});
//Fire the event
$evManager->fire('custom:custom', null);
//Get all the collected responses
print_r($evManager->getResponses());
Вышеупомянутый пример даёт:
Array ( [0] => first response [1] => second response )
Реализация собственного EventsManager
Интерфейс Phalcon\Events\ManagerInterface должен быть реализован для создания собственного EventsManager, заменяя тот, который предоставляется Phalcon.
© 2011–2016 Phalcon Framework Team
Licensed under the Creative Commons Attribution License 3.0.
https://docs.phalconphp.com/en/2.0.0/reference/events.html