Events - uniqcle/Yii2 GitHub Wiki
- Назвать событие. Например, "Пользователь зарегестрировался"
- Создать действие/обработчик
- Навешать этот обработчик на событие
- Вызвать выполнение события
In Controller
навешиваем действия к событию
frontend\controllers\UserController.php
namespace frontend\controllers;
use Yii;
use frontend\models\forms\SignupForm;
use frontend\models\forms\LoginForm;
use frontend\models\User;
class UserController extends \yii\web\Controller
{
public function actionSignup(){
...
}
public function actionLogin(){
...
}
public function actionLogout(){
...
}
public function actionEvents(){
$user = new User();
//СОЗДАЕМ И НАВЕШИВАЕМ ДЕЙСТВИЯ К СОБЫТИЮ
//В ней методы навызывания и отвязывания действий по отношению к событию on(), off()
//on(Название события, само действие, кот. нужно сделать после этого события)
$user->on(USER::USER_REGISTERED, function($event){
var_dump($event->name); //Выводит названия события
var_dump($event->sender); //Та модель, в кот. было взывано событие
var_dump($event->data); // Доп. инфа, передается 3-м параметром после действия. Строка, массив, др. объект
var_dump('Вызов события 1');
}, 'Дополнительная информация');
//Действия можно передать 4-мя способами
#1 Callback. Как выше
#2 Передать объект, 2-й параметр - метод в этом объекте
$user->on(USER::USER_REGISTERED, [$user, 'methodFromObject']);
#3 Если в другой модели.
//Путь к этому классу и название статичного метода
$user->on(USER::USER_REGISTERED, ['frontend\models\User', 'staticMethodFromClass']);
#4 Использование глобальных ф-ий PHP
$user->on(USER::USER_REGISTERED, 'get_class' );
//ВЫЗОВ СОБЫТИЯ
$user->trigger(USER::USER_REGISTERED);
}
}
В модели User frontend\models\User.php
namespace frontend\models;
use Yii;
use yii\web\IdentityInterface;
class User extends \yii\db\ActiveRecord implements IdentityInterface
{
//НАЗЫВАЕМ СОБЫТИЕ
//Константа с названием события
const USER_REGISTERED = 'user registered';
public static function tableName(){
return 'user';
}
public function rules(){
...
}
...
public function methodFromObject($event){
var_dump('Вызов события 2');
$event->handled = true; //После этого дальнейшие действия в события прекращаются.
}
public static function staticMethodFromClass(){
var_dump('Вызов события 3');
}
...
}
In Model
В методе init() навешиваем действия к событию
frontend\controllers\UserController.php
namespace frontend\controllers;
use Yii;
use frontend\models\forms\SignupForm;
use frontend\models\forms\LoginForm;
use frontend\models\User;
class UserController extends \yii\web\Controller
{
public function actionSignup(){ }
public function actionLogin(){ }
public function actionLogout(){
}
public function actionEvents(){
$user = new User();
$user->userRegistered();
}
}
Модель frontend\models\User.php
namespace frontend\models;
use Yii;
use yii\web\IdentityInterface;
class User extends \yii\db\ActiveRecord implements IdentityInterface
{
//НАЗЫВАЕМ СОБЫТИЕ
//Константа с названием события
const USER_REGISTERED = 'user registered';
public function init(){
//СОЗДАЕМ И НАВЕШИВАЕМ ДЕЙСТВИЯ К СОБЫТИЮ
//В ней методы навызывания и отвязывания действий по отношению к событию on(), off()
//on(Название события, само действие, кот. нужно сделать после этого события)
$this->on(USER::USER_REGISTERED, function($event){
var_dump($event->name); //Выводит названия события
var_dump($event->sender); //Та модель, в кот. было взывано событие
var_dump($event->data); // Доп. инфа, передается 3-м параметром после действия. Строка, массив, др. объект
var_dump('Вызов события 1');
}, 'Дополнительная информация');
//Действия можно передать 4-мя способами
#1 Callback. Как выше
#2 Передать объект, 2-й параметр - метод в этом объекте
$this->on(USER::USER_REGISTERED, [$this, 'methodFromObject']);
#3 Если в другой модели.
//Путь к этому классу и название статичного метода
$this->on(USER::USER_REGISTERED, ['frontend\models\User', 'staticMethodFromClass']);
#4 Использование глобальных ф-ий PHP
$this->on(USER::USER_REGISTERED, 'get_class' );
}
public function userRegistered(){
//ВЫЗОВ СОБЫТИЯ
$this->trigger(USER::USER_REGISTERED);
}
public function methodFromObject($event){
var_dump('Вызов события 2');
$event->handled = true; //После этого дальнейшие действия в события прекращаются.
}
public static function staticMethodFromClass(){
var_dump('Вызов события 3');
}
public static function tableName(){
return 'user';
}
...
Service as Component
Контроллер frontend\controllers\UserController.php
namespace frontend\controllers;
use Yii;
use frontend\models\forms\SignupForm;
use frontend\models\forms\LoginForm;
use frontend\models\User;
class UserController extends \yii\web\Controller
{
//Register
public function actionSignup()
{
$model = new SignupForm();
if($model->load( Yii::$app->request->post() ) && $user = $model->save() ){
Yii::$app->user->login( $user );
Yii::$app->session->setFlash('success', 'New user added!');
return $this->redirect(['site/index']);
}
return $this->render('signup', [
'model' => $model
]);
}
//Login
public function actionLogin(){
$model = new LoginForm();
if( $model->load( Yii::$app->request->post() ) && $model->login() ){
Yii::$app->session->setFlash('success', 'Вы успешно авторизовались!');
return $this->redirect(['/site/index']);
}
return $this->render('login', [
'model' => $model
]);
}
public function actionLogout(){
Yii::$app->user->logout();
return $this->redirect(['site/index']);
}
}
В модели frontend\models\forms\SignupForm
после валидации и сохранения данных пользователя в БД вместо вызова методов компонента, вызываем событие $user->userRegistered($event)
, в кот. подключены методы, а в нем передаем объект $event
, куда записываем все данные по данному событию.
namespace frontend\models\forms;
use Yii;
use yii\base\Model;
use frontend\models\User;
use frontend\models\events\UserRegisterEvent;
class SignupForm extends Model
{
public $username;
public $email;
public $password;
public function rules(){
return [
['username', 'string', 'min' => 2, 'max' => 255],
['username', 'required'],
['username', 'trim'],
['username', 'unique', 'targetClass' => User::className() ],
['email', 'trim'],
['email', 'required'],
['email', 'email'],
['email', 'string', 'min' => 2, 'max' => 255],
['email', 'unique', 'targetClass' => User::className() ],
['password', 'required'],
['password', 'string', 'min' => 2, 'max' => 255]
];
}
public function save(){
$user = new User();
if( $this->validate() ){
$user->username = $this->username;
$user->auth_key = Yii::$app->security->generateRandomString();
$user->password_hash = Yii::$app->security->generatePasswordHash( $this->password );
$user->email = $this->email;
$user->created_at = $time = time();
$user->updated_at = $time;
if( $user->save() ){
//Объекта паттерна Data Transfer Object
$event = new UserRegisterEvent();
$event->user = $user;
$event->subject = 'New user registered';
//Вызов события
$user->userRegistered($event);
/*
Yii::$app->emailService->notifyUser($user, 'Welcome');
Yii::$app->emailService->notifyAdmins('User registered'); */
/*Yii::$app->smsService->notifyUser($user);
Yii::$app->smsService->notifyAdmins('User registered');
Yii::$app->postService->sendGift($user);
other actions
other actions
other actions
*/
return $user;
}
}
return false;
}
}
В модели frontend\models\User.php
в методе init()
подключаем обработчики к событию.
namespace frontend\models;
use Yii;
use yii\web\IdentityInterface;
use common\components\UserNotificationInterface;
class User extends \yii\db\ActiveRecord implements IdentityInterface
{
//НАЗЫВАЕМ СОБЫТИЕ. Константа с названием события
const USER_REGISTERED = 'user_registered';
public function init(){
//Навешиваем обработчик на событие. 1 парам - объект, 2 парам. - метод
$this->on(self::USER_REGISTERED, [Yii::$app->emailService, 'notifyAdmins']);
$this->on(self::USER_REGISTERED, [Yii::$app->emailService, 'notifyUser']);
parent::init();
}
public function userRegistered($event){
//ВЫЗОВ СОБЫТИЯ
$this->trigger(USER::USER_REGISTERED, $event);
}
public static function tableName()
{
return 'user';
}
public function rules()
{
return [
[['username', 'auth_key', 'password_hash', 'email', 'created_at', 'updated_at'], 'required'],
[['status', 'created_at', 'updated_at'], 'integer'],
[['username', 'password_hash', 'password_reset_token', 'email'], 'string', 'max' => 255],
[['auth_key'], 'string', 'max' => 32],
[['username'], 'unique'],
[['email'], 'unique'],
[['password_reset_token'], 'unique'],
];
}
public function attributeLabels()
{
return [
'id' => 'ID',
'username' => 'Username',
'auth_key' => 'Auth Key',
'password_hash' => 'Password Hash',
'password_reset_token' => 'Password Reset Token',
'email' => 'Email',
'status' => 'Status',
'created_at' => 'Created At',
'updated_at' => 'Updated At',
];
}
public function getUserByUsername($username){
return self::find()->where(['username' => $username ])->one();
}
public function validatePassword($password){
return Yii::$app->security->validatePassword($password, $this->password_hash);
}
//IDENTITY INTERFACE
public static function findIdentity($id)
{
return static::findOne($id);
}
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['access_token' => $token]);
}
public function getId()
{
return $this->id;
}
public function getAuthKey()
{
return $this->auth_key;
}
public function validateAuthKey($authKey)
{
return $this->getAuthKey() === $authKey;
}
}
Класс компонента common\components\EmailService.php
namespace common\components;
use Yii;
//Чтобы использовать этот класс как компонент приложения, нужно расширить от Component
use yii\base\Component;
use common\components\UserNotificationInterface;
class EmailService extends Component
{
public function notifyUser(UserNotificationInterface $event){
Yii::$app->mailer->compose()
->setFrom( '[email protected]' )
->setTo( $event->getEmail() )
->setSubject( $event->getSubject() )
->setTextBody('Новый клиент') // Закомментировать, если передаем в View
/*->setHtmlBody('Текст...')*/
->send();
}
public function notifyAdmins(UserNotificationInterface $event){
Yii::$app->mailer->compose()
->setFrom( '[email protected]' )
->setTo( '[email protected]' )
->setSubject( $event->getSubject() )
->setTextBody('Новый клиент') // Закомментировать, если передаем в View
/*->setHtmlBody('Текст...')*/
->send();
}
}
Класс frontend\models\events\UserRegisterEvent.php
, в кот. будет передаваться данные для события
namespace frontend\models\events;
use yii\base\Event;
use frontend\models\User;
use common\components\UserNotificationInterface;
class UserRegisterEvent extends Event implements UserNotificationInterface
{
public $user;
public $subject;
public function getUser(){
return $this->user;
}
public function getEmail(){
return $this->user->email;
}
public function getSubject(){
return $this->subject;
}
}
Интерфейс common\components\UserNotificationInterface.php
необходим для контроля типов и какие методы должен реализовывать переходный класс UserRegisterEvent
namespace common\components;
interface UserNotificationInterface
{
public function getEmail();
public function getSubject();
}
Проверить настройки в подключении компонентов common\config\main.php
...
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
],
/// Компонент почты
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '@common/mail',
'transport' => [
'class' => 'Swift_SmtpTransport',
'host' => 'smtp.yandex.ru',
'username' => '[email protected]', //
'password' => '2207kirill',
'port' => '465',
'encryption' => 'ssl', // у яндекса SSL
],
'useFileTransport' => false, // будем отправлять реальные сообщения, а не в файл
],
// Подключаем компонент сервиса
'emailService' => [
'class' => 'common\components\EmailService'
],
],