Search code examples
cakephpeventscallbackcakephp-3.0cakephp-3.1

CakePHP 3: How to create custom model callbacks?


Need good start point to create custom model callbacks. For specific part of application i can't use default cakephp lifecycle callbacks (beforeSave, afterSave,..) because table is large. In controller I create more methods wich partial update records, for example users 4 step registrations.

How to create custom model callbacks for example beforeRegister used only before new user account created?


Solution

  • Rather than using callback methods which are more of a CakePHP 2.x concept, I would recommend dispatching Events which you can then listen to.

    The book has a chapter about Events.

    Specifically, you'll want to dispatch your new event, using a name which includes the layer you're working in.

    // Inside a controller
    $event = new \Cake\Event\Event(
        // The name of the event, including the layer and event
        'Controller.Registration.stepFour', 
        // The subject of the event, usually where it's coming from, so in this case the controller
        $this, 
        // Any extra stuff we want passed to the event
        ['user' => $userEntity] 
    );
    $this->eventManager()->dispatch($event);
    

    Then you can listen to the event in another part of your application. For me personally, in most cases I like to create a specific listener class, in my src/Lib/Listeners folder.

    namespace App\Lib\Listeners;
    
    class RegistrationListener implements EventListenerInterface
    {
        public function implementedEvents()
        {
            return [
                'Controller.Registration.stepOne' => 'stepOne'
                'Controller.Registration.stepFour' => 'stepFour'
        }
    
        public function stepOne(\Cake\Event\Event $event, \Cake\Datasource\EntityInterface $user)
        {
            // Process your step here
        }
    }
    

    Then you need to bind the listener. To do this I tend to use the global Event Manager instance and do it in my AppController, so that it can listen everywhere, but if you're just working with a single RegistrationsController you might want to attach it just to that one controller.

    Attaching globally, probably in your AppController::initialize()

    EventManager::instance()->on(new \App\Lib\RegistrationListener());
    

    Attaching to a controller, probably in your Controller::initialize()

    $this->eventManager()->on(new \App\Lib\RegistrationListener())