Grigory Volkov
Grigory Volkov

Reputation: 482

Yii2 : Creating custom Global event

I have login form, and after the user successfully logs in, I want an event to fire. The event must have two functions sendMail and notification. To achieve this I have done the following steps:

  1. In my User model create a EVENT_NEW_USER constant.
  2. Create sendMail and notification functions.
  3. Create an init function, in which I try to attach my functions to the event.

Here is how my model code looks like:

<?php

namespace app\models;
use yii\base\Component;

class User extends \yii\db\ActiveRecord implements  \yii\web\IdentityInterface
{

    const EVENT_NEW_USER='new_user';

    public function sendMail($event){
        echo 'mail sent to admin';
    }

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

    public function init(){

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

        parent::init(); 
    }
}

Inside my actionLogin function of my controller I check if the user has logged in and try to make the event work with trigger:

public function actionLogin()
{
    $model = new LoginForm();

    if ($model->load(Yii::$app->request->post()) && $model->login()) {

        $model->trigger(User::EVENT_NEW_USER); 

    }
    else{
        return $this->render('login',['model' => $model]);
    }
}

But I am getting a blank page. What is not correct in my code and how can I fix it?

Upvotes: 0

Views: 620

Answers (1)

Muhammad Omer Aslam
Muhammad Omer Aslam

Reputation: 23738

What looks like you are trying to create an event for the afterLogin, I would attach it to the controller rather than the model, and I would use a conventional approach to do that so you keep your code separate and clean.

Add a constant in the controller where you have the login action

const EVENT_AFTER_LOGIN = 'afterLogin';

Create an event handler class and add a handler function that would send the email

<?php
    namespace common\components\handlers;

    class LoginHandler
{
    /**
     * Handles the after login event process to send emails
     *
     * @param FormEvent $event Event object form
     *
     * @return null
     */
    public static function handleAfterLogin(\common\components\events\FormEvent $event)
    {
       ///.. your code to send emails 
    }
}

Create a FormEvent class

<?php

namespace common\components\events;

use yii\base\Event;
use yii\base\Model;

class FormEvent extends Event
{
    /**
     * @var Model
     */
    private $_form;

    /**
     * @return Model
     */
    public function getForm()
    {
        return $this->_form;
    }

    /**
     * @param Model $form
     */
    public function setForm(Model $form)
    {
        $this->_form = $form;
    }
}

Create the init function in your controller like below

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

        //bind after confirmation event
        $this->on(
            self::EVENT_AFTER_LOGIN,
            [
                new \common\components\handlers\LoginHandler(),
                'handleAfterLogin',
            ]
        );
}

Now add the following method in your controller

 /**
 * Return the FormEvent
 *
 * @param FormEvent $form the form model object
 *
 * @return FormEvent
 * @throws \yii\base\InvalidConfigException
 */
protected function getFormEvent(\common\components\events\FormEvent $form)
{
    return \Yii::createObject(['class' => \common\components\events\FormEvent::class, 'form' => $form]);
}

And then in your login action

public function actionLogin()
{
    $model = Yii::createObject(LoginForm::class);

    //get the event
    $event = $this->getFormEvent($model);

    if ($model->load(Yii::$app->request->post()) && $model->login()) {
         //trigger the after login handler
         $this->trigger(self::EVENT_AFTER_LOGIN, $event);
    }
    else{
        return $this->render('login',['model' => $model]);
    }
}

Now if you add print_r($event) inside you handleAfterLogin method you will see the object and its properties loaded with the user added info you can get the email using $event->username or whatever field name you have and add your code to send email in the handleAfterLogin.

Upvotes: 1

Related Questions