[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管理
- 请求环境
- 返回响应
- 安全
- 加密/解密
- 安全
- 国际化
- 国际化
- 多语言支持