[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` |
- 常規
- Welcome
- 貢獻
- 生成回溯
- 測試重現
- 單元測試
- 入門
- 安裝
- Web服務器設置
- WAMP
- XAMPP
- 教程
- 基礎教程
- 教程:創建一個簡單的REST API
- 教程:V?kuró
- 提升性能
- 教程:INVO
- 開發環境
- Phalcon Compose (Docker)
- Nanobox
- Phalcon Box (Vagrant)
- 開發工具
- Phalcon開發者工具的安裝
- Phalcon開發者工具的使用
- 調試應用程序
- 核心
- MVC應用
- 微應用
- 創建命令行(CLI)應用程序
- 依賴注入與服務定位
- MVC架構
- 服務
- 使用緩存提高性能
- 讀取配置
- 上下文轉義
- 類加載器
- 使用命名空間
- 日志
- 隊列
- 數據庫
- 數據庫抽象層
- Phalcon查詢語言(PHQL)
- ODM(對象文檔映射器)
- 使用模型
- 模型行為
- ORM緩存
- 模型事件
- 模型元數據
- 模型關系
- 模型事務
- 驗證模型
- 數據庫遷移
- 分頁
- 前端
- Assets管理
- 閃存消息
- 表單
- 圖像
- 視圖助手(標簽)
- 使用視圖
- Volt:模板引擎
- 業務邏輯
- 訪問控制列表(ACL)
- 注解解析器
- 控制器
- 調度控制器
- 事件管理器
- 過濾與清理
- 路由
- 在session中存儲數據
- 生成URL和路徑
- 驗證
- HTTP
- Cookies管理
- 請求環境
- 返回響應
- 安全
- 加密/解密
- 安全
- 國際化
- 國際化
- 多語言支持