多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
#### 事件与事件管理器(Events and Events Manager) Models allow you to implement events that will be thrown when performing an insert/update/delete. They help define business rules for a certain model. The following are the events supported by Phalcon\Mvc\Model and their order of execution: 模型允许您实现在执行插入/更新/删除时将抛出的事件。它们帮助为特定的模型定义业务规则。以下是Phalcon\Mvc\Model和他们的执行顺序所支持的事件: | Operation 操作 | Name | Can stop operation? 是否停止操作 | Explanation 解释 | | --- | --- | --- | --- | | Inserting/Updating | beforeValidation | YES | Is executed before the fields are validated for not nulls/empty strings or foreign keys 在字段被验证为非空/空字符串或外键之前执行 | | Inserting | beforeValidationOnCreate | YES | Is executed before the fields are validated for not nulls/empty strings or foreign keys when an insertion operation is being made 在执行插入操作时,在字段被验证之前执行,而不是空/空字符串或外键 | | Updating | beforeValidationOnUpdate | YES | Is executed before the fields are validated for not nulls/empty strings or foreign keys when an updating operation is being made 在进行更新操作时,在字段被验证之前执行,而不是空/空字符串或外键。 | | Inserting/Updating | onValidationFails | YES (already stopped) | Is executed after an integrity validator fails 在完整性验证器失败后执行 | | Inserting | afterValidationOnCreate | YES | Is executed after the fields are validated for not nulls/empty strings or foreign keys when an insertion operation is being made 在执行插入操作时,在字段被验证后执行,而不是空/空字符串或外键 | | Updating | afterValidationOnUpdate | YES | Is executed after the fields are validated for not nulls/empty strings or foreign keys when an updating operation is being made 当一个更新操作被执行时,在字段被验证为非空/空字符串或外键时执行。 | | Inserting/Updating | afterValidation | YES | Is executed after the fields are validated for not nulls/empty strings or foreign keys 在字段被验证为非空/空字符串或外键后执行 | | Inserting/Updating | beforeSave | YES | Runs before the required operation over the database system 在数据库系统上运行之前运行 | | Updating | beforeUpdate | YES | Runs before the required operation over the database system only when an updating operation is being made 只有当正在进行更新操作时,才需要在数据库系统上运行所需的操作 | | Inserting | beforeCreate | YES | Runs before the required operation over the database system only when an inserting operation is being made 只有在进行插入操作时,才需要在数据库系统上运行所需的操作 | | Updating | afterUpdate | NO | Runs after the required operation over the database system only when an updating operation is being made 仅当正在进行更新操作时,才需要在数据库系统上运行所需的操作。 | | Inserting | afterCreate | NO | Runs after the required operation over the database system only when an inserting operation is being made 只有在进行插入操作时,才需要在数据库系统上运行所需的操作 | | Inserting/Updating | afterSave | afterSave | Runs after the required operation over the database system 在数据库系统上运行所需的操作之后运行 | #### 模型中自定义事件(Implementing Events in the Model’s class) The easier way to make a model react to events is implement a method with the same name of the event in the model’s class: 使模型对事件作出反应的更简单的方法是在模型类中实现一个具有相同名称的方法: ~~~ <?php namespace Store\Toys; use Phalcon\Mvc\Model; class Robots extends Model { public function beforeValidationOnCreate() { echo "This is executed before creating a Robot!"; } } ~~~ Events can be useful to assign values before performing an operation, for example: 在执行操作之前,事件可以很有用地分配值,例如: ~~~ <?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"); } } ~~~ #### 使用自定义事件管理器(Using a custom Events Manager) Additionally, this component is integrated with Phalcon\Events\Manager, this means we can create listeners that run when an event is triggered. 此外,该组件与事件管理器集成,这意味着我们可以创建在触发事件时运行的侦听器。 ~~~ <?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); } } ~~~ In the example given above, the Events Manager only acts as a bridge between an object and a listener (the anonymous function). Events will be fired to the listener when ‘robots’ are saved: 在上面给出的示例中,事件管理器仅充当对象和侦听器(匿名函数)之间的桥梁。当“robots”被保存时,事件将被触发。 ~~~ <?php use Store\Toys\Robots; $robot = new Robots(); $robot->name = "Scooby Doo"; $robot->year = 1969; $robot->save(); ~~~ If we want all objects created in our application use the same EventsManager, then we need to assign it to the Models Manager: 如果我们想要在我们的应用程序中创建的所有对象使用同一个EventsManager,那么我们需要将它分配给模型管理器: ~~~ <?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; } ); ~~~ If a listener returns false that will stop the operation that is executing currently. 如果侦听器返回false,将停止当前正在执行的操作。 #### 记录底层 SQL 语句(Logging Low-Level SQL Statements) When using high-level abstraction components such as Phalcon\Mvc\Model to access a database, it is difficult to understand which statements are finally sent to the database system. Phalcon\Mvc\Model is supported internally by Phalcon\Db. Phalcon\Logger interacts with Phalcon\Db, providing logging capabilities on the database abstraction layer, thus allowing us to log SQL statements as they happen. 当使用诸如“Phalcon\Mvc\Model”这样的高级抽象组件来访问数据库时,很难理解哪些语句最终被发送到数据库系统。“Phalcon\Mvc\Model”模式是由“Phalcon\Db”数据库在内部支持的。在数据库抽象层上提供Phalcon\Logger记录功能,从而允许我们记录SQL语句的发生。 ~~~ <?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; } ); ~~~ As models access the default database connection, all SQL statements that are sent to the database system will be logged in the file: 当模型访问默认数据库连接时,发送到数据库系统的所有SQL语句都将被记录在文件中: ~~~ <?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"; } ~~~ As above, the file app/logs/db.log will contain something like this: 如上所述,文件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 语句(Profiling SQL Statements) Thanks to Phalcon\Db, the underlying component of Phalcon\Mvc\Model, it’s possible to profile the SQL statements generated by the ORM in order to analyze the performance of database operations. With this you can diagnose performance problems and to discover bottlenecks. 由于使用了“Phalcon\Db“,Phalcon\Mvc\Model模型的底层组件,可以对ORM生成的SQL语句进行概要分析,从而分析数据库操作的性能。通过这种方法,您可以诊断性能问题并发现瓶颈。 ~~~ <?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; } ); ~~~ Profiling some queries: 分析一些查询: ~~~ <?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"; } ~~~ Each generated profile contains the duration in milliseconds that each instruction takes to complete as well as the generated SQL statement. 每个生成的概要文件包含了每条指令完成的时间和生成的SQL语句的持续时间。