SearchTable Of ContentsPrevious topicNext topicThis Page |
事件管理¶此组件的目的是通过创建挂钩点拦截框架中大部分组件的执行。这些挂钩点允许开发者获取状态信息,操作数据或改变一个组件在执行过程中的流程。 译者注:挂钩点(hooks point)类似于SVN或GIT中的hook。在使用SVN开发过程中,我们想实现把提交的代码直接部署到演示环境下,那么就需要SVN的hook. 使用示例¶在下面的例子中,我们使用EventsManager侦听使用 Phalcon\Db 进行MySQL连接管理过程中产生的事件。首先,我们需要一个侦听器对象,我们创建一个类,它的方法是我们要侦听的事件: <?php
class MyDbListener
{
public function afterConnect()
{
}
public function beforeQuery()
{
}
public function afterQuery()
{
}
}
这个新的类文件可以更详细一些,因为我们需要使用它。EventsManager 将充当组件与侦听器之间的桥梁,为我们创建的侦听类的方法提供挂钩点: <?php
$eventsManager = new \Phalcon\Events\Manager();
//Create a database listener
$dbListener = new MyDbListener()
//Listen all the database events
$eventsManager->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”。第一个参数传递给 事件侦听器,包含正在运行的事件的上下文信息,第二个是连接本身。 <?php
class MyDbListener
{
protected $_logger;
public function __construct()
{
$this->_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语句比预期花费多长时间: <?php
class MyDbListener
{
protected $_profiler;
protected $_logger;
public function __construct()
{
$this->_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;
}
}
可以从监听器获得返回的数据: <?php
//Send a SQL command to the database server
$connection->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形式的匿名函数来执行任务,而不是一个单独的监听器类(见上面示例): <?php
//Listen all the database events
$eventManager->attach('db', function($event, $connection) {
if ($event->getType() == 'afterQuery') {
echo $connection->getSQLStatement();
}
});
Creating components that trigger Events¶你也可以在应用程序中创建自己的组件,使用EventsManager触发事件。作为结果,事件运行时监听器会作出相应的反应。在下面的例子中,我们创建了一个叫”MyComponent”的组件。这个组件实现了EventsManager aware接口,当它的方法 “someTask” 执行时,监听器会触发相应的两个事件: <?php
class MyComponent implements \Phalcon\Events\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”,这是一个唯一标志字符,以帮助我们知道事件是由哪个组件产生的。你甚至可以在组件之个创建相同名称的事件。现在,让我们来创建一个监听器监听这个组件: <?php
class SomeListener
{
public function beforeSomeTask($event, $myComponent)
{
echo "Here, beforeSomeTask\n";
}
public function afterSomeTask($event, $myComponent)
{
echo "Here, afterSomeTask\n";
}
}
一个监听器就是一个简单的类文件,它实现了所有组件触发的事件。现在,让我们使他们联合在一起工作: <?php
//Create an Events Manager
$eventsManager = new Phalcon\Events\Manager();
//Create the MyComponent instance
$myComponent = new MyComponent();
//Bind the eventsManager to the instance
$myComponent->setEventsManager($myComponent);
//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” 调用第三个参数进行触发: <?php
$eventsManager->fire("my-component:afterSomeTask", $this, $extraData);
在监听器中,第三个参数也接收此数据: <?php
//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());
});
如果监听器只对一个特定类型的事件感兴趣,你可以直接绑定: <?php
//The handler will only be executed if the event triggered is "beforeSomeTask"
$eventManager->attach('my-component:beforeSomeTask', function($event, $component) {
//...
});
事件的发布与取消(Event Propagation/Cancelation)¶许多监听器可能会添加相同的事件,这意味着,对于同类类型的事件,许多监听器都会被触发(即会有非常多同类型的消息输出)。根据注册到 EventsManager 的顺序,监听器被一一触发。一些事件可以被撤消,表明可以停止一些其他的监听器事件被触发: <?php
$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();
}
//...
});
在默认情况下,事件是可以被取消的,甚至在框架中的大部分事件都是可以被取消的。你可以使用fire方法传递第四个参数,值为”false”,以达到不可取消的目的: <?php
$eventsManager->fire("my-component:afterSomeTask", $this, $extraData, false);
实现自定义EventsManager(Implementing your own EventsManager)¶The Phalcon\Events\ManagerInterface interface must be implemented to create your own EventsManager replacing the one provided by Phalcon. |