事件管理器
最后更新于:2022-04-02 05:15:15
[TOC]
# 事件管理器
该组件的目的是通过创建“钩子”来拦截框架的大多数其他组件的执行。这些挂钩点允许开发人员在组件处理期间获取状态信息,操纵数据或更改执行流程。
## 命名惯例
Phalcon事件使用命名空间来避免命名冲突。Phalcon中的每个组件都占用不同的事件名称空间,您可以根据需要自由创建自己的名称空间。事件名称格式为`component:event`。例如,当`Phalcon\Db` 占用`db`命名空间时,其`afterQuery`事件的全名是`db:afterQuery`。
将事件侦听器附加到事件管理器时,可以使用`组件`来捕获该组件中的所有事件(例如,`db`以捕获所有`Phalcon\Db`事件)或`component:event`来定位特定事件(例如`db:afterQuery`)。
## 用例
在下面的示例中,我们将使用EventsManager侦听由`Phalcon\Db`管理的MySQL连接中生成的`afterQuery`事件:
```php
attach(
'db:afterQuery',
function (Event $event, $connection) {
echo $connection->getSQLStatement();
}
);
$connection = new DbAdapter(
[
'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语句。传递给lambda函数的第一个参数包含有关正在运行的事件的上下文信息,第二个参数是事件的来源(在本例中是连接本身)。还可以指定第三个参数,该参数将包含特定于该事件的任意数据。
>[warning] 必须使用`setEventsManager()`方法将事件管理器显式设置为组件,以便该组件触发事件。您可以为每个组件创建新的事件管理器实例,也可以将相同的事件管理器设置为多个组件,因为命名约定可以避免冲突。
您可以使用事件侦听器类,而不是使用lambda函数。事件侦听器还允许您侦听多个事件。在这个例子中,我们将实现`Phalcon\Db\Profiler`来检测执行时间比预期更长的SQL语句:
```php
profiler = new Profiler();
$this->logger = new Logger('../apps/logs/db.log');
}
/**
* This is executed if the event triggered is 'beforeQuery'
*/
public function beforeQuery(Event $event, $connection)
{
$this->profiler->startProfile(
$connection->getSQLStatement()
);
}
/**
* This is executed if the event triggered is 'afterQuery'
*/
public function afterQuery(Event $event, $connection)
{
$this->logger->log(
$connection->getSQLStatement(),
Logger::INFO
);
$this->profiler->stopProfile();
}
public function getProfiler()
{
return $this->profiler;
}
}
```
将事件侦听器附加到事件管理器非常简单:
```php
attach(
'db',
$dbListener
);
```
可以从侦听器获取生成的配置文件数据:
```php
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';
}
```
## 创建触发事件的组件
您可以在应用程序中创建触发EventManager事件的组件。因此,可能存在在生成时对这些事件作出反应的侦听器。在下面的示例中,我们将创建一个名为`MyComponent`的组件。该组件是EventsManager感知的(它实现了`Phalcon\Events\EventsAwareInterface`);当执行`someTask()`方法时,它会向EventsManager中的任何侦听器触发两个事件:
```php
eventsManager = $eventsManager;
}
public function getEventsManager()
{
return $this->eventsManager;
}
public function someTask()
{
$this->eventsManager->fire('my-component:beforeSomeTask', $this);
// Do some task
echo 'Here, someTask\n';
$this->eventsManager->fire('my-component:afterSomeTask', $this);
}
}
```
请注意,在此示例中,我们使用的是`my-component`事件命名空间。现在我们需要为这个组件创建一个事件监听器:
```php
setEventsManager($eventsManager);
// Attach the listener to the EventsManager
$eventsManager->attach(
'my-component',
new SomeListener()
);
// Execute methods in the component
$myComponent->someTask();
```
当执行 `someTask()` 时,将执行侦听器中的两个方法,从而产生以下输出:
```bash
Here, beforeSomeTask
Here, someTask
Here, afterSomeTask
```
使用 `fire()`的第三个参数触发事件时,也可能传递其他数据:
```php
fire('my-component:afterSomeTask', $this, $extraData);
```
在侦听器中,第三个参数也接收此数据:
```php
attach(
'my-component',
function (Event $event, $component, $data) {
print_r($data);
}
);
// Receiving the data from the event context
$eventsManager->attach(
'my-component',
function (Event $event, $component) {
print_r($event->getData());
}
);
```
## 使用来自DI的服务
通过继承`Phalcon\Mvc\User\Plugin`,您可以从DI访问服务,就像在控制器中一样:
```php
logger->debug(
'beforeSomeTask has been triggered'
);
}
public function afterSomeTask(Event $event, $myComponent)
{
echo 'Here, afterSomeTask\n';
$this->logger->debug(
'afterSomeTask has been triggered'
);
}
}
```
## 事件通知/取消
许多听众可能会被添加到同一个事件管理器中。这意味着对于相同类型的事件,可以通知许多侦听器。将按照它们在EventsManager中注册的顺序通知侦听器。某些事件是可取消的,表示可能会停止这些事件,以防止其他侦听器收到有关该事件的通知:
```php
attach(
'db',
function (Event $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();
}
// ...
}
);
```
默认情况下,事件是可取消的 - 即使框架生成的大多数事件都是可取消的。您可以通过在`fire()`的第四个参数中传递`false`来触发不可取消的事件:
```php
fire('my-component:afterSomeTask', $this, $extraData, false);
```
## 侦听优先级
附加侦听器时,您可以设置特定的优先级。使用此功能,您可以附加指示必须调用它们的顺序的侦听器:
```php
enablePriorities(true);
$eventsManager->attach('db', new DbListener(), 150); // More priority
$eventsManager->attach('db', new DbListener(), 100); // Normal priority
$eventsManager->attach('db', new DbListener(), 50); // Less priority
```
## 收集响应
事件管理器可以收集每个通知的侦听器返回的每个响应。此示例说明了它的工作原理:
```php
collectResponses(true);
// Attach a listener
$eventsManager->attach(
'custom:custom',
function () {
return 'first response';
}
);
// Attach a listener
$eventsManager->attach(
'custom:custom',
function () {
return 'second response';
}
);
// Fire the event
$eventsManager->fire('custom:custom', null);
// Get all the collected responses
print_r($eventsManager->getResponses());
```
上面的例子生成:
```php
Array ( [0] => first response [1] => second response )
```
## 实现自己的EventsManager
必须实现`Phalcon\Events\ManagerInterface`接口才能创建自己的EventsManager,取代Phalcon提供的EventManager。
## 事件列表
Phalcon提供的事件包括:
| 组件 | 事件 |
| ------------------ | ----------------------------------- |
| ACL | `acl:afterCheckAccess` |
| ACL | `acl:beforeCheckAccess` |
| Application | `application:afterHandleRequest` |
| Application | `application:afterStartModule` |
| Application | `application:beforeHandleRequest` |
| Application | `application:beforeSendResponse` |
| Application | `application:beforeStartModule` |
| Application | `application:boot` |
| Application | `application:viewRender` |
| CLI | `dispatch:beforeException` |
| Collection | `afterCreate` |
| Collection | `afterSave` |
| Collection | `afterUpdate` |
| Collection | `afterValidation` |
| Collection | `afterValidationOnCreate` |
| Collection | `afterValidationOnUpdate` |
| Collection | `beforeCreate` |
| Collection | `beforeSave` |
| Collection | `beforeUpdate` |
| Collection | `beforeValidation` |
| Collection | `beforeValidationOnCreate` |
| Collection | `beforeValidationOnUpdate` |
| Collection | `notDeleted` |
| Collection | `notSave` |
| Collection | `notSaved` |
| Collection | `onValidationFails` |
| Collection | `validation` |
| Collection Manager | `collectionManager:afterInitialize` |
| Console | `console:afterHandleTask` |
| Console | `console:afterStartModule` |
| Console | `console:beforeHandleTask` |
| Console | `console:beforeStartModule` |
| Db | `db:afterQuery` |
| Db | `db:beforeQuery` |
| Db | `db:beginTransaction` |
| Db | `db:createSavepoint` |
| Db | `db:commitTransaction` |
| Db | `db:releaseSavepoint` |
| Db | `db:rollbackTransaction` |
| Db | `db:rollbackSavepoint` |
| Dispatcher | `dispatch:afterExecuteRoute` |
| Dispatcher | `dispatch:afterDispatch` |
| Dispatcher | `dispatch:afterDispatchLoop` |
| Dispatcher | `dispatch:afterInitialize` |
| Dispatcher | `dispatch:beforeException` |
| Dispatcher | `dispatch:beforeExecuteRoute` |
| Dispatcher | `dispatch:beforeDispatch` |
| Dispatcher | `dispatch:beforeDispatchLoop` |
| Dispatcher | `dispatch:beforeForward` |
| Dispatcher | `dispatch:beforeNotFoundAction` |
| Loader | `loader:afterCheckClass` |
| Loader | `loader:beforeCheckClass` |
| Loader | `loader:beforeCheckPath` |
| Loader | `loader:pathFound` |
| Micro | `micro:afterHandleRoute` |
| Micro | `micro:afterExecuteRoute` |
| Micro | `micro:beforeExecuteRoute` |
| Micro | `micro:beforeHandleRoute` |
| Micro | `micro:beforeNotFound` |
| Middleware | `afterBinding` |
| Middleware | `afterExecuteRoute` |
| Middleware | `afterHandleRoute` |
| Middleware | `beforeExecuteRoute` |
| Middleware | `beforeHandleRoute` |
| Middleware | `beforeNotFound` |
| Model | `afterCreate` |
| Model | `afterDelete` |
| Model | `afterSave` |
| Model | `afterUpdate` |
| Model | `afterValidation` |
| Model | `afterValidationOnCreate` |
| Model | `afterValidationOnUpdate` |
| Model | `beforeDelete` |
| Model | `notDeleted` |
| Model | `beforeCreate` |
| Model | `beforeDelete` |
| Model | `beforeSave` |
| Model | `beforeUpdate` |
| Model | `beforeValidation` |
| Model | `beforeValidationOnCreate` |
| Model | `beforeValidationOnUpdate` |
| Model | `notSave` |
| Model | `notSaved` |
| Model | `onValidationFails` |
| Model | `prepareSave` |
| Models Manager | `modelsManager:afterInitialize` |
| Request | `request:afterAuthorizationResolve` |
| Request | `request:beforeAuthorizationResolve` |
| Router | `router:beforeCheckRoutes` |
| Router | `router:beforeCheckRoute` |
| Router | `router:matchedRoute` |
| Router | `router:notMatchedRoute` |
| Router | `router:afterCheckRoutes` |
| Router | `router:beforeMount` |
| View | `view:afterRender` |
| View | `view:afterRenderView` |
| View | `view:beforeRender` |
| View | `view:beforeRenderView` |
| View | `view:notFoundView` |
| Volt | `compileFilter` |
| Volt | `compileFunction` |
| Volt | `compileStatement` |
| Volt | `resolveExpression` |
';