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:

    1. <?php
    2. use Phalcon\Mvc\Model;
    3. class Products extends Model
    4. {
    5. public function beforeCreate()
    6. {
    7. // Set the creation date
    8. $this->created_at = date('Y-m-d H:i:s');
    9. }
    10. public function beforeUpdate()
    11. {
    12. // Set the modification date
    13. $this->modified_in = date('Y-m-d H:i:s');
    14. }
    15. }

    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.

    1. <?php
    2. namespace Store\Toys;
    3. use Phalcon\Mvc\Model;
    4. use Phalcon\Events\Event;
    5. use Phalcon\Events\Manager as EventsManager;
    6. class Robots extends Model
    7. {
    8. public function initialize()
    9. {
    10. $eventsManager = new EventsManager();
    11. // Attach an anonymous function as a listener for 'model' events
    12. $eventsManager->attach(
    13. 'model:beforeSave',
    14. function (Event $event, $robot) {
    15. if ($robot->name === 'Scooby Doo') {
    16. echo "Scooby Doo isn't a robot!";
    17. return false;
    18. }
    19. return true;
    20. }
    21. );
    22. // Attach the events manager to the event
    23. $this->setEventsManager($eventsManager);
    24. }
    25. }

    If we want all objects created in our application use the same EventsManager, then we need to assign it to the Models Manager:

    1. <?php
    2. use Phalcon\Events\Event;
    3. use Phalcon\Events\Manager as EventsManager;
    4. // Registering the modelsManager service
    5. $di->setShared(
    6. 'modelsManager',
    7. function () {
    8. // Attach an anonymous function as a listener for 'model' events
    9. $eventsManager->attach(
    10. 'model:beforeSave',
    11. function (Event $event, $model) {
    12. if (get_class($model) === \Store\Toys\Robots::class) {
    13. if ($model->name === 'Scooby Doo') {
    14. echo "Scooby Doo isn't a robot!";
    15. return false;
    16. }
    17. }
    18. return true;
    19. }
    20. );
    21. // Setting a default EventsManager
    22. $modelsManager = new ModelsManager();
    23. $modelsManager->setEventsManager($eventsManager);
    24. return $modelsManager;
    25. }
    26. );

    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.

    1. <?php
    2. use Phalcon\Logger;
    3. use Phalcon\Events\Manager;
    4. use Phalcon\Logger\Adapter\File as FileLogger;
    5. use Phalcon\Db\Adapter\Pdo\Mysql as Connection;
    6. $di->set(
    7. 'db',
    8. function () {
    9. $eventsManager = new EventsManager();
    10. $logger = new FileLogger('app/logs/debug.log');
    11. // Listen all the database events
    12. $eventsManager->attach(
    13. 'db:beforeQuery',
    14. function ($event, $connection) use ($logger) {
    15. $logger->log(
    16. $connection->getSQLStatement(),
    17. Logger::INFO
    18. );
    19. }
    20. );
    21. $connection = new Connection(
    22. [
    23. 'host' => 'localhost',
    24. 'username' => 'root',
    25. 'password' => 'secret',
    26. 'dbname' => 'invo',
    27. ]
    28. );
    29. // Assign the eventsManager to the db adapter instance
    30. $connection->setEventsManager($eventsManager);
    31. return $connection;
    32. }
    33. );

    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.

    1. <?php
    2. use Phalcon\Db\Profiler as ProfilerDb;
    3. use Phalcon\Events\Manager as EventsManager;
    4. use Phalcon\Db\Adapter\Pdo\Mysql as MysqlPdo;
    5. 'profiler',
    6. function () {
    7. return new ProfilerDb();
    8. true
    9. );
    10. $di->set(
    11. 'db',
    12. function () use ($di) {
    13. $eventsManager = new EventsManager();
    14. // Get a shared instance of the DbProfiler
    15. $profiler = $di->getProfiler();
    16. // Listen all the database events
    17. $eventsManager->attach(
    18. 'db',
    19. function ($event, $connection) use ($profiler) {
    20. if ($event->getType() === 'beforeQuery') {
    21. $profiler->startProfile(
    22. $connection->getSQLStatement()
    23. );
    24. }
    25. if ($event->getType() === 'afterQuery') {
    26. $profiler->stopProfile();
    27. }
    28. }
    29. );
    30. $connection = new MysqlPdo(
    31. [
    32. 'host' => 'localhost',
    33. 'username' => 'root',
    34. 'password' => 'secret',
    35. 'dbname' => 'invo',
    36. ]
    37. );
    38. // Assign the eventsManager to the db adapter instance
    39. $connection->setEventsManager($eventsManager);
    40. return $connection;
    41. }
    42. );

    Profiling some queries:

    1. <?php
    2. use Store\Toys\Robots;
    3. // Send some SQL statements to the database
    4. Robots::find();
    5. Robots::find(
    6. [
    7. 'order' => 'name',
    8. ]
    9. );
    10. Robots::find(
    11. [
    12. 'limit' => 30,
    13. ]
    14. );
    15. // Get the generated profiles from the profiler
    16. $profiles = $di->get('profiler')->getProfiles();
    17. foreach ($profiles as $profile) {
    18. echo 'SQL Statement: ', $profile->getSQLStatement(), '\n';
    19. echo 'Start Time: ', $profile->getInitialTime(), '\n';
    20. echo 'Final Time: ', $profile->getFinalTime(), '\n';
    21. echo 'Total Elapsed Time: ', $profile->getTotalElapsedSeconds(), '\n';
    22. }

    Each generated profile contains the duration in milliseconds that each instruction takes to complete as well as the generated SQL statement.