事件管理 ============== 此组件的目的是通过创建挂钩点拦截框架中大部分组件的执行。这些挂钩点允许开发者获取状态信息,操作数据或改变一个组件在执行过程中的流程。 译者注:挂钩点(hooks point)类似于SVN或GIT中的hook。在使用SVN开发过程中,我们想实现把提交的代码直接部署到演示环境下,那么就需要SVN的hook. 使用示例 ------------- 在下面的例子中,我们使用EventsManager侦听使用 :doc:`Phalcon\\Db <../api/Phalcon_Db>` 进行MySQL连接管理过程中产生的事件。首先,我们需要一个侦听器对象,我们创建一个类,它的方法是我们要侦听的事件: .. code-block:: php attach('db', $dbListener); $connection = new \Phalcon\Db\Adapter\Pdo\Mysql(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”。第一个参数传递给 事件侦听器,包含正在运行的事件的上下文信息,第二个是连接本身。 .. code-block:: php _logger = new \Phalcon\Logger\Adapter\File("../apps/logs/db.log"); } public function afterQuery($event, $connection) { $this->_logger->log($connection->getSQLStatement(), \Phalcon\Logger::INFO); } } 作为示例的一部分,我们需要实现 Phalcon\\Db\\Profiler,以检测SQL语句比预期花费多长时间: .. code-block:: php _profiler = new \Phalcon\Db\Profiler(); $this->_logger = new \Phalcon\Logger\Adapter\File("../apps/logs/db.log"); } public function beforeQuery($event, $connection) { $this->_profiler->startProfile($connection->getSQLStatement()); } public function afterQuery($event, $connection) { $this->_logger->log($connection->getSQLStatement(), \Phalcon\Logger::INFO); $this->_profiler->stopProfile(); } public function getProfiler() { return $this->_profiler; } } 可以从监听器获得返回的数据: .. code-block:: php query("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"; } 以类似的方式,我们可以注册一个lambda形式的匿名函数来执行任务,而不是一个单独的监听器类(见上面示例): .. code-block:: php attach('db', function($event, $connection) { if ($event->getType() == 'afterQuery') { echo $connection->getSQLStatement(); } }); Creating components that trigger Events --------------------------------------- 你也可以在应用程序中创建自己的组件,使用EventsManager触发事件。作为结果,事件运行时监听器会作出相应的反应。在下面的例子中,我们创建了一个叫"MyComponent"的组件。这个组件实现了EventsManager aware接口,当它的方法 "someTask" 执行时,监听器会触发相应的两个事件: .. code-block:: php _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",这是一个唯一标志字符,以帮助我们知道事件是由哪个组件产生的。你甚至可以在组件之个创建相同名称的事件。现在,让我们来创建一个监听器监听这个组件: .. code-block:: php setEventsManager($myComponent); //Attach the listener to the EventsManager $eventsManager->attach('my-component', new SomeListener()); //Execute methods in the component $myComponent->someTask(); "someTask"执行后,监听器中的两个方法也会被执行,下面是输出结果: .. code-block:: php Here, beforeSomeTask Here, afterSomeTask 其他数据也可以通过 "fire" 调用第三个参数进行触发: .. code-block:: php fire("my-component:afterSomeTask", $this, $extraData); 在监听器中,第三个参数也接收此数据: .. code-block:: php 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()); }); 如果监听器只对一个特定类型的事件感兴趣,你可以直接绑定: .. code-block:: php attach('my-component:beforeSomeTask', function($event, $component) { //... }); 事件的发布与取消(Event Propagation/Cancelation) ------------------------------------------------------------------ 许多监听器可能会添加相同的事件,这意味着,对于同类类型的事件,许多监听器都会被触发(即会有非常多同类型的消息输出)。根据注册到 EventsManager 的顺序,监听器被一一触发。一些事件可以被撤消,表明可以停止一些其他的监听器事件被触发: .. code-block:: php 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(); } //... }); 在默认情况下,事件是可以被取消的,甚至在框架中的大部分事件都是可以被取消的。你可以使用fire方法传递第四个参数,值为"false",以达到不可取消的目的: .. code-block:: php fire("my-component:afterSomeTask", $this, $extraData, false); 实现自定义EventsManager(Implementing your own EventsManager) --------------------------------------------------------------------------- The :doc:`Phalcon\\Events\\ManagerInterface <../api/Phalcon_Events_ManagerInterface>` interface must be implemented to create your own EventsManager replacing the one provided by Phalcon.