需求.
- 用户登陆成功根据用户的专业给用户推送产品.
- 用户登陆成功给用户发送一封邮件
- 用户登陆成功判断后一次登陆时间如果超过1个月告诉通知营销部门
- 用户登陆成功如果角色是超级管理员自动跳转到 /admin/contents 页面
- 用户登陆成功如果角色是网站管理员自动跳转到 /manage页面
先定义一个模块来完成我们的需求. 模块名为.
普通的做法
use Drupal\user\UserInterface;
/**
* Implements hook_user_login().
*
* @param UserInterface $account
* @throws \Drupal\Core\Entity\EntityMalformedException
*/
function observer_user_login(UserInterface $account) {
// ############# 用户登陆成功根据用户的专业给用户推送产品. ########## //
switch ($account->get('field_profession')->value) {
case 'A':
//一大堆逻辑
break;
case 'B':
// 一大堆逻辑
break;
case 'C':
// 一大堆逻辑
break;
default:
// 一大堆逻辑
break;
}
// ############# 用户登陆成功给用户发送一封邮件. ########## //
// 发送邮件逻辑
// ############# 用户登陆成功判断后一次登陆时间如果超过1个月告诉通知营销部门. ########## //
if (time() - $account->get('access')->value > 3000) {
// 通知营销部门逻辑
}
// ############# 用户登陆成功如果角色是超级管理员自动跳转到 /admin/contents 页面. ########## //
if ($account->hasRole('administrator')) {
// 跳转逻辑
}
// ############# 用户登陆成功如果角色是网站管理员自动跳转到 /manage页面. ########## //
if ($account->hasRole('webmaster')) {
// 跳转逻辑
}
}
这里的代码越后面会越乱,如果到时再增加一个需求登陆成功要做某事。可能又是一大堆逻辑.
现在改用普通的PHP观察者模式分离代码
PHP观察者模式
定义: src/Observer.php
<?php
namespace Drupal\observer;
use Drupal\user\UserInterface;
/**
* 创建主题用来注册所有的观察者.
*
* Class Observer
*/
class Observer implements \SplSubject {
private array $observers = [];
private UserInterface $account;
public function setAccount(UserInterface $account) {
$this->account = $account;
}
public function getAccount() {
return $this->account;
}
/**
* 注册观察者.
*
* @param \SplObserver $observer
*/
public function attach(\SplObserver $observer):void {
$this->observers[] = $observer;
}
/**
* 移掉观察者.
*
* @param \SplObserver $observer
*/
public function detach(\SplObserver $observer):void {
if ($key = array_search($observer,$this->observers, true)){
unset($this->observers[$key]);
}
}
/**
* 通知观察者.
*/
public function notify():void {
foreach ($this->observers as $value) {
$value->update($this);
}
}
}
分别定义功能代码:
src/Observers/Notice.php
src/Observers/NoticeMarkting.php
src/Observers/PushProduct.php
src/Observers/RedAdmin.php
src/Observers/RedWebmaster.php
代码都类似如下。只是类名不一样.
<?php
namespace Drupal\observer\Observers;
use Drupal\observer\Observer;
use SplSubject;
class Notice implements \SplObserver {
public function update(Observer|SplSubject $subject):void {
$account = $subject->getAccount();
\Drupal::logger('observer')->notice('用户登陆成功给用户发送一封邮件: ' . $account->label());
}
}
然后修改hook
<?php
use Drupal\observer\Observers\Notice;
use Drupal\observer\Observers\NoticeMarkting;
use Drupal\observer\Observers\PushProduct;
use Drupal\observer\Observers\RedAdmin;
use Drupal\observer\Observers\RedWebmaster;
use Drupal\user\UserInterface;
use Drupal\observer\Observer;
/**
* Implements hook_user_login().
*
* @param UserInterface $account
*/
function observer_user_login(UserInterface $account) {
$observer = new Observer();
$observer->setAccount($account);
$observer->attach(new Notice());
$observer->attach(new NoticeMarkting());
$observer->attach(new PushProduct());
$observer->attach(new RedAdmin());
$observer->attach(new RedWebmaster());
$observer->notify();
}
Drupal的event和hook就很类似观察者模式. 现在可以使用event来实现这段代码
Event实现
这里定义一个新的模块: obevent
先自定义一个用户登陆的事件: src/Event/UserLoginEvent.php
<?php
namespace Drupal\obevent\Event;
use Drupal\Component\EventDispatcher\Event;
use Drupal\user\UserInterface;
class UserLoginEvent extends Event {
const EVENT_NAME = 'custom_event_user_login';
/**
* @var \Drupal\user\UserInterface
*/
public UserInterface $account;
public function getAccount() {
return $this->account;
}
public function setAccount($account) {
$this->account = $account;
}
public function __construct(UserInterface $account) {
$this->setAccount($account);
}
}
定义功能实现的服务: obevent.services.yml
services:
obevent.user_login_notice_event_subscriber:
class: Drupal\obevent\EventSubscriber\LoginNoticeSubscriber
tags:
- { name: event_subscriber }
obevent.user_login_notice_markting_event_subscriber:
class: Drupal\obevent\EventSubscriber\LoginNoticeMarktingSubscriber
tags:
- { name: event_subscriber }
obevent.user_login_push_product_event_subscriber:
class: Drupal\obevent\EventSubscriber\LoginPushProductSubscriber
tags:
- { name: event_subscriber }
obevent.user_login_red_admin_subscriber:
class: Drupal\obevent\EventSubscriber\LoginRedAdminSubscriber
tags:
- { name: event_subscriber }
obevent.user_login_red_webmater_subscriber:
class: Drupal\obevent\EventSubscriber\LoginRedWebmasterSubscriber
tags:
- { name: event_subscriber }
定义功能实现代码:
src/EventSubscriber/LoginNoticeMarktingSubscriber.php
src/EventSubscriber/LoginNoticeSubscriber.php
src/EventSubscriber/LoginPushProductSubscriber.php
src/EventSubscriber/LoginRedAdminSubscriber.php
src/EventSubscriber/LoginRedWebmasterSubscriber.php
功能类似下面这样. 只是类名不一样
<?php
declare(strict_types=1);
namespace Drupal\obevent\EventSubscriber;
use Drupal\obevent\Event\UserLoginEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
final class LoginNoticeSubscriber implements EventSubscriberInterface {
/**
* Kernel request event handler.
*/
public function onUserLogin(UserLoginEvent $event): void {
$account = $event->getAccount();
\Drupal::logger('observer')->notice('用户登陆成功给用户发送一封邮件: ' . $account->label());
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
return [
UserLoginEvent::EVENT_NAME => ['onUserLogin'],
];
}
}
修改obevent.module文件.
<?php
use Drupal\obevent\Event\UserLoginEvent;
use Drupal\user\UserInterface;
/**
* Implements hook_user_login().
*
* @param UserInterface $account
*/
function obevent_user_login(UserInterface $account) {
$event = new UserLoginEvent($account);
\Drupal::service('event_dispatcher')->dispatch($event, UserLoginEvent::EVENT_NAME);
}