35

I've been through the documentation and all the articles on Yii2 events found using Google. Can someone provide me a good example of how events can be used in Yii2 and where it may seem logical?

Ejaz Karim
  • 3,495
  • 6
  • 33
  • 48
nirajan poudel
  • 632
  • 1
  • 8
  • 13
  • May be this example help for you - http://stackoverflow.com/questions/25847013/yii2-multiple-event-attach-on-view – vitalik_74 Feb 18 '15 at 05:15

3 Answers3

86

I can explain events by a simple example. Let's say, you want to do few things when a user first registers to the site like:

  1. Send an email to the admin.
  2. Create a notification.
  3. you name it.

You may try to call a few methods after a user object is successfully saved. Maybe like this:

if($model->save()){
   $mailObj->sendNewUserMail($model);
   $notification->setNotification($model);
}

So far it may seem fine but what if the number of requirements grows with time? Say 10 things must happen after a user registers himself? Events come handy in situations like this.

Basics of events

Events are composed of the following cycle.

  1. You define an event. Say, new user registration.
  2. You name it in your model. Maybe adding constant in User model. Like const EVENT_NEW_USER='new_user';. This is used to add handlers and to trigger an event.
  3. You define a method that should do something when an event occurs. Sending an email to Admin for example. It must have an $event parameter. We call this method a handler.
  4. You attach that handler to the model using its a method called on(). You can call this method many times you wish - simply you can attach more than one handler to a single event.
  5. You trigger the event by using trigger().

Note that, all the methods mentioned above are part of Component class. Almost all classes in Yii2 have inherited form this class. Yes ActiveRecord too.

Let's code

To solve above mentioned problem we may have User.php model. I'll not write all the code here.

// in User.php i've declared constant that stores event name
const EVENT_NEW_USER = 'new-user';

// say, whenever new user registers, below method will send an email.
public function sendMail($event){
   echo 'mail sent to admin';
   // you code 
}

// one more hanlder.

public function notification($event){
  echo 'notification created';
}

One thing to remember here is that you're not bound to create methods in the class that creates an event. You can add any static, non static method from any class.

I need to attach above handlers to the event . The basic way I did is to use AR's init() method. So here is how:

// this should be inside User.php class.
public function init(){

  $this->on(self::EVENT_NEW_USER, [$this, 'sendMail']);
  $this->on(self::EVENT_NEW_USER, [$this, 'notification']);

  // first parameter is the name of the event and second is the handler. 
  // For handlers I use methods sendMail and notification
  // from $this class.
  parent::init(); // DON'T Forget to call the parent method.
}

The final thing is to trigger an event. Now you don't need to explicitly call all the required methods as we did before. You can replace it by following:

if($model->save()){
  $model->trigger(User::EVENT_NEW_USER); 
}

All the handlers will be automatically called.

112Legion
  • 668
  • 6
  • 19
Ejaz Karim
  • 3,495
  • 6
  • 33
  • 48
  • 2
    Very good and thorough example there, helped me a lot. Can I also use this type of implementation for wordpress like plugin development? If so can you illustrate like above. – nirajan poudel Feb 19 '15 at 10:38
  • 3
    @nirajanpoudel sorry, I'm not Wordpress guy. – Ejaz Karim Feb 19 '15 at 15:48
  • 1
    This helped a lot. if i want to attach to the global $app where do I define the event handlers like in your answer, you defined it in the init() of the user model? – user1502826 May 30 '15 at 19:42
  • @EjazKarim bahi: I have same requirement in Yii 1 but I have used afterSave instead of events. Can you tell me issues of afterSave thanks – Samar Haider Sep 01 '15 at 04:26
  • 1
    afterSave is database related event, you will use it when you need to do something after record gets saved. But in other cases you need to write custom events. – Ejaz Karim Sep 01 '15 at 13:58
  • 2
    Another important thing: put the actions in a `afterSave()` or in a `if($model->save())` block will make those actions be run ever in those blocks. But if you use an `Event`, you can control it (turn on and off as you want). I mean that sometimes you won't to run those actions, so you won't attach any event. But when you need those actions so you just do `$myModel->on('myEvent', [$myModel, 'myAction1'])` and they will be run when 'myEvent' happen. Your actions are now optional according to your system necessities. – sdlins Dec 25 '16 at 14:02
24

For "global" events.

Optionally you can create a specialized event class

namespace  your\handler\Event\Namespace;
class EventUser extends Event {
   const EVENT_NEW_USER = 'new-user';
}

define at least one handler class:

namespace  your\handler\Event\Namespace;
class handlerClass{
    // public AND static
    public static function handleNewUser(EventUser $event)
    {
        // $event->user contain the "input" object
        echo 'mail sent to admin for'. $event->user->username;
    }
}

Inside the component part of the config under (in this case) the user component insert you event:

'components' => [
  'user' => [
    ...
    'on new-user' => ['your\handler\Event\Namespace\handlerClass', 'handleNewUser'],
  ],
  ...
]

Then in your code you can trigger the event:

Yii::$app->user->trigger(EventUser::EVENT_NEW_USER, new EventUser($user));

ADD

You can also use a closure:

  • allows IDE to "detect" the use of the function (for code navigation)
  • put some (small) code that manage the event

example:

'components' => [
  'user' => [
    ...
    'on new-user' => function($param){ your\handler\Event\Namespace\handlerClass::handleNewUser($param);},
    'on increment' => function($param){ \Yii::$app->count += $param->value;},
  ],   
  ... 
]
Ivan Buttinoni
  • 3,775
  • 1
  • 19
  • 33
  • any ideas why using `$this` inside the handle function throws an exception `"Using $this when not in object context",` for example if i have a private property defined with private `$_myVar` and calling `$this->_myVar` throws above exception – Reborn Dec 17 '18 at 11:38
  • If I remember correctly, you are not really "inside" the object, so you cannot access that scope. Can you create a new question with the code? – Ivan Buttinoni Dec 19 '18 at 08:47
  • we do define the handle function "inside a class" and set it via config like `'on eventName'=> [ 'app\events\SubscriptionEvents', 'handleAfterTerminated', ],` and then if i define a private class property how come i cant access it via `$this` residing in the same handle function but can still access the property or function if i declare them static and call then via `self`. – Reborn Dec 19 '18 at 10:45
  • which php version? 5.6 or 7.x? – Ivan Buttinoni Dec 19 '18 at 13:58
  • I have php `V7.2` installed – Reborn Dec 19 '18 at 14:03
  • I think, but not sure because I still didn't use 7.2, that call_user_func (used by trigger to call the closure), define *self* but not *this*, see: http://php.net/manual/en/function.call-user-func.php#refsect1-function.call-user-func-changelog – Ivan Buttinoni Dec 19 '18 at 23:56
  • @MuhammadOmerAslam I found another motivation of this behavior, but I need more infos so pls create a new question. – Ivan Buttinoni Dec 20 '18 at 06:01
4

By default Yii2 already provide some event declaration, You can read more about explanation on BaseActiveRecord.

You can use this variable as same as declaring it manually.

public function init()
{
    parent::init();

    $this->on(self::EVENT_AFTER_INSERT, [$this, 'exampleMethodHere']);
}
elfarqy
  • 151
  • 1
  • 4