🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 事件管理器 该组件的目的是通过创建“钩子”来拦截框架的大多数其他组件的执行。这些挂钩点允许开发人员在组件处理期间获取状态信息,操纵数据或更改执行流程。 ## 命名惯例 Phalcon事件使用命名空间来避免命名冲突。Phalcon中的每个组件都占用不同的事件名称空间,您可以根据需要自由创建自己的名称空间。事件名称格式为`component:event`。例如,当`Phalcon\Db` 占用`db`命名空间时,其`afterQuery`事件的全名是`db:afterQuery`。 将事件侦听器附加到事件管理器时,可以使用`组件`来捕获该组件中的所有事件(例如,`db`以捕获所有`Phalcon\Db`事件)或`component:event`来定位特定事件(例如`db:afterQuery`)。 ## 用例 在下面的示例中,我们将使用EventsManager侦听由`Phalcon\Db`管理的MySQL连接中生成的`afterQuery`事件: ```php <?php use Phalcon\Events\Event; use Phalcon\Events\Manager as EventsManager; use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter; $eventsManager = new EventsManager(); $eventsManager->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 <?php use Phalcon\Db\Profiler; use Phalcon\Events\Event; use Phalcon\Logger; use 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 $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 <?php // Create a database listener $dbListener = new MyDbListener(); // Listen all the database events $eventsManager->attach( 'db', $dbListener ); ``` 可以从侦听器获取生成的配置文件数据: ```php <?php // 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'; } ``` ## 创建触发事件的组件 您可以在应用程序中创建触发EventManager事件的组件。因此,可能存在在生成时对这些事件作出反应的侦听器。在下面的示例中,我们将创建一个名为`MyComponent`的组件。该组件是EventsManager感知的(它实现了`Phalcon\Events\EventsAwareInterface`);当执行`someTask()`方法时,它会向EventsManager中的任何侦听器触发两个事件: ```php <?php use Phalcon\Events\EventsAwareInterface; use Phalcon\Events\Manager as EventsManager; class MyComponent implements EventsAwareInterface { protected $eventsManager; public function setEventsManager(EventsManager $eventsManager) { $this->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 <?php use Phalcon\Events\Event; class SomeListener { public function beforeSomeTask(Event $event, $myComponent) { echo "Here, beforeSomeTask\n"; } public function afterSomeTask(Event $event, $myComponent) { echo "Here, afterSomeTask\n"; } } ``` 现在让我们让一切都协同工作: ```php <?php use Phalcon\Events\Manager as EventsManager; // Create an Events Manager $eventsManager = new EventsManager(); // 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()` 时,将执行侦听器中的两个方法,从而产生以下输出: ```bash Here, beforeSomeTask Here, someTask Here, afterSomeTask ``` 使用 `fire()`的第三个参数触发事件时,也可能传递其他数据: ```php <?php $eventsManager->fire('my-component:afterSomeTask', $this, $extraData); ``` 在侦听器中,第三个参数也接收此数据: ```php <?php use Phalcon\Events\Event; // Receiving the data in the third parameter $eventsManager->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 <?php use Phalcon\Events\Event; use Phalcon\Mvc\User\Plugin; class SomeListener extends Plugin { public function beforeSomeTask(Event $event, $myComponent) { echo 'Here, beforeSomeTask\n'; $this->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 <?php use Phalcon\Events\Event; $eventsManager->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 <?php $eventsManager->fire('my-component:afterSomeTask', $this, $extraData, false); ``` ## 侦听优先级 附加侦听器时,您可以设置特定的优先级。使用此功能,您可以附加指示必须调用它们的顺序的侦听器: ```php <?php $eventsManager->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 <?php use Phalcon\Events\Manager as EventsManager; $eventsManager = new EventsManager(); // Set up the events manager to collect responses $eventsManager->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` |