2025-04-14

需求.

  1. 用户登陆成功根据用户的专业给用户推送产品.
  2. 用户登陆成功给用户发送一封邮件
  3. 用户登陆成功判断后一次登陆时间如果超过1个月告诉通知营销部门
  4. 用户登陆成功如果角色是超级管理员自动跳转到 /admin/contents 页面
  5. 用户登陆成功如果角色是网站管理员自动跳转到 /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);
}
标签: PHP 设计模式