Model Events
Models allow you to implement events that will be thrown while performing an insert/update/delete which can be used to define business rules. The following are the events supported by Phalcon\Mvc\Model and their order of execution:
The easier way to make a model react to events is to implement a method with the same name of the event in the model’s class:
Events can be used 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);
}
}
If we want all objects created in our application use the same EventsManager, then we need to assign it to the Models Manager:
<?php
use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;
// Registering the modelsManager service
$di->setShared(
'modelsManager',
function () {
// Attach an anonymous function as a listener for 'model' events
$eventsManager->attach(
'model:beforeSave',
function (Event $event, $model) {
if (get_class($model) === \Store\Toys\Robots::class) {
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.
When using high-level abstraction components such as 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\Logger interacts with , providing logging capabilities on the database abstraction layer, thus allowing us to log SQL statements as they happen.
<?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:
Thanks to Phalcon\Db, the underlying component of , 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.
<?php
use Phalcon\Db\Profiler as ProfilerDb;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Db\Adapter\Pdo\Mysql as MysqlPdo;
'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.