[TOC]
# 模型事件
## 事件與事件管理
模型允許您實現在執行插入/更新/刪除時將拋出的事件,這些事件可用于定義業務規則。以下是 `Phalcon\Mvc\Model` 支持的事件及其執行順序:
| 操作 | 名稱 | Can stop operation? | 說明 |
| ------------------ | ------------------------ |:---------------------:| --------------------------------------------------------------------------------------------------------------------------------- |
| Inserting | afterCreate | NO | 僅在進行插入操作時,在數據庫系統上執行所需操作后運行 |
| Deleting | afterDelete | NO | 刪除操作完成后運行 |
| Updating | afterUpdate | NO | 僅在進行更新操作時,在數據庫系統上執行所需操作后運行 |
| Inserting/Updating | afterSave | NO | 在數據庫系統上執行所需的操作后運行 |
| Inserting/Updating | afterValidation | YES | 在為非空/空字符串或外鍵驗證字段后執行 |
| Inserting | afterValidationOnCreate | YES | 在進行插入操作時,在字段驗證非空/空字符串或外鍵之后執行 |
| Updating | afterValidationOnUpdate | YES | 在進行更新操作時,在對字段進行非空/空字符串或外鍵驗證之后執行 |
| Inserting/Updating | beforeValidation | YES | 在字段驗證非空/空字符串或外鍵之前執行|
| Inserting | beforeCreate | YES | 僅在進行插入操作時才在數據庫系統上執行所需操作之前運行 |
| Deleting | beforeDelete | YES | 在執行刪除操作之前運行 |
| Inserting/Updating | beforeSave | YES |在數據庫系統上執行所需的操作之前運行 |
| Updating | beforeUpdate | YES | 僅在進行更新操作時才在數據庫系統上執行所需操作之前運行 |
| Inserting | beforeValidationOnCreate | YES | 在進行插入操作時,在字段驗證非空值/空字符串或外鍵之前執行 |
| Updating | beforeValidationOnUpdate | YES | 在進行更新操作時,在字段驗證非空值/空字符串或外鍵之前執行 |
| Inserting/Updating | onValidationFails | YES (already stopped) | 在完整性驗證程序失敗后執行 |
| Inserting/Updating | validation | YES | 在進行更新操作時,在字段驗證非空值/空字符串或外鍵之前執行 |
### 在Model的類中實現事件
使模型對事件做出反應的更簡單方法是在模型的類中實現與事件名稱相同的方法:
```php
<?php
namespace Store\Toys;
use Phalcon\Mvc\Model;
class Robots extends Model
{
public function beforeValidationOnCreate()
{
echo 'This is executed before creating a Robot!';
}
}
```
事件可用于在執行操作之前分配值,例如:
```php
<?php
use Phalcon\Mvc\Model;
class Products extends Model
{
public function beforeCreate()
{
// Set the creation date
$this->created_at = date('Y-m-d H:i:s');
}
public function beforeUpdate()
{
// Set the modification date
$this->modified_in = date('Y-m-d H:i:s');
}
}
```
### 使用自定義事件管理器
此外,該組件與`Phalcon\Events\Manager`集成,這意味著我們可以創建在觸發事件時運行的偵聽器。
```php
<?php
namespace Store\Toys;
use Phalcon\Mvc\Model;
use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;
class Robots extends Model
{
public function initialize()
{
$eventsManager = new EventsManager();
// Attach an anonymous function as a listener for 'model' events
$eventsManager->attach(
'model:beforeSave',
function (Event $event, $robot) {
if ($robot->name === 'Scooby Doo') {
echo "Scooby Doo isn't a robot!";
return false;
}
return true;
}
);
// Attach the events manager to the event
$this->setEventsManager($eventsManager);
}
}
```
在上面給出的示例中,事件管理器僅充當對象和偵聽器(匿名函數)之間的橋梁。保存`robots`時,將觸發監聽事件:
```php
<?php
use Store\Toys\Robots;
$robot = new Robots();
$robot->name = 'Scooby Doo';
$robot->year = 1969;
$robot->save();
```
如果我們希望在我們的應用程序中創建的所有對象使用相同的EventsManager,那么我們需要將它分配給Models Manager:
```php
<?php
use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;
// Registering the modelsManager service
$di->setShared(
'modelsManager',
function () {
$eventsManager = new EventsManager();
// Attach an anonymous function as a listener for 'model' events
$eventsManager->attach(
'model:beforeSave',
function (Event $event, $model) {
// Catch events produced by the Robots model
if (get_class($model) === 'Store\Toys\Robots') {
if ($model->name === 'Scooby Doo') {
echo "Scooby Doo isn't a robot!";
return false;
}
}
return true;
}
);
// Setting a default EventsManager
$modelsManager = new ModelsManager();
$modelsManager->setEventsManager($eventsManager);
return $modelsManager;
}
);
```
如果偵聽器返回false,將停止當前正在執行的操作。
## 記錄底層SQL語句
當使用諸如 `Phalcon\Mvc\Model` 之類的高級抽象組件來訪問數據庫時,很難理解哪些語句最終被發送到數據庫系統。`Phalcon\Mvc\Model` 由`Phalcon\Db`內部支持。`Phalcon\Logger`與`Phalcon\Db`交互,在數據庫抽象層上提供日志記錄功能,從而允許我們在SQL語句發生時記錄它們。
```php
<?php
use Phalcon\Logger;
use Phalcon\Events\Manager;
use Phalcon\Logger\Adapter\File as FileLogger;
use Phalcon\Db\Adapter\Pdo\Mysql as Connection;
$di->set(
'db',
function () {
$eventsManager = new EventsManager();
$logger = new FileLogger('app/logs/debug.log');
// Listen all the database events
$eventsManager->attach(
'db:beforeQuery',
function ($event, $connection) use ($logger) {
$logger->log(
$connection->getSQLStatement(),
Logger::INFO
);
}
);
$connection = new Connection(
[
'host' => 'localhost',
'username' => 'root',
'password' => 'secret',
'dbname' => 'invo',
]
);
// Assign the eventsManager to the db adapter instance
$connection->setEventsManager($eventsManager);
return $connection;
}
);
```
當模型訪問默認數據庫連接時,發送到數據庫系統的所有SQL語句都將記錄在文件中:
```php
<?php
use Store\Toys\Robots;
$robot = new Robots();
$robot->name = 'Robby the Robot';
$robot->created_at = '1956-07-21';
if ($robot->save() === false) {
echo 'Cannot save robot';
}
```
如上所述,文件*app/logs/db.log*將包含以下內容:
> `[Mon, 30 Apr 12 13:47:18 -0500][DEBUG][Resource Id #77] INSERT INTO robots` `(name, created_at) VALUES ('Robby the Robot', '1956-07-21')`
## 分析SQL語句
由于`Phalcon\Db`是`Phalcon\Mvc\Model`的底層組件,因此可以分析ORM生成的SQL語句,以分析數據庫操作的性能。通過這種方式,您可以診斷性能問題并發現瓶頸。
```php
<?php
use Phalcon\Db\Profiler as ProfilerDb;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Db\Adapter\Pdo\Mysql as MysqlPdo;
$di->set(
'profiler',
function () {
return new ProfilerDb();
},
true
);
$di->set(
'db',
function () use ($di) {
$eventsManager = new EventsManager();
// Get a shared instance of the DbProfiler
$profiler = $di->getProfiler();
// Listen all the database events
$eventsManager->attach(
'db',
function ($event, $connection) use ($profiler) {
if ($event->getType() === 'beforeQuery') {
$profiler->startProfile(
$connection->getSQLStatement()
);
}
if ($event->getType() === 'afterQuery') {
$profiler->stopProfile();
}
}
);
$connection = new MysqlPdo(
[
'host' => 'localhost',
'username' => 'root',
'password' => 'secret',
'dbname' => 'invo',
]
);
// Assign the eventsManager to the db adapter instance
$connection->setEventsManager($eventsManager);
return $connection;
}
);
```
分析一些查詢:
```php
<?php
use Store\Toys\Robots;
// Send some SQL statements to the database
Robots::find();
Robots::find(
[
'order' => 'name',
]
);
Robots::find(
[
'limit' => 30,
]
);
// Get the generated profiles from the profiler
$profiles = $di->get('profiler')->getProfiles();
foreach ($profiles 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";
}
```
每個生成的配置文件都包含每條指令完成所需的持續時間(以毫秒為單位)以及生成的SQL語句。
- 常規
- 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管理
- 請求環境
- 返回響應
- 安全
- 加密/解密
- 安全
- 國際化
- 國際化
- 多語言支持