Drupal中使用路由监听
Introduction
介绍一下在Drupal中使用路由监听来实现访问特定的url,或者根据自定义规则进行路由重定向
Step1: Define module
我们首先创建一个自定义模块,模块的名字叫做 Test redirect,同时在模块文件夹里面定义模块的基本信息,写在test_redirect.info.yml里面。
name: 'Test redirect'
type: module
description: 'This is a test module.'
core_version_requirement: '^8 || ^9'
package: 'Test'
Step2: Define module service config file
第二部我们给模块注册一个服务,定义一个service文件,在模块文件夹里面定义一下服务信息,写在test_redirect.services.yml里面。
services:
test.event_subscriber: #服务名称
class: Drupal\test\EventSubscriber\RedirectSubscriber # 服务所在的命名空间
arguments: ['@current_user','@file_url_generator'] #服务构造参数的依赖注入
tags: #服务标识,event_subscriber代表我们这个服务是一个时间订阅服务
- { name: event_subscriber }
Step3: Create RedirectSubscriber file
在最后一步中,我们根据在模块服务配置文件中创建的内容,来自定义一个重定向的时间订阅类,在类里面去处理我们自己的业务逻辑,大概代码如下,关键部分我会给出解释。
<?php
namespace Drupal\test\EventSubscriber;
use Drupal\Core\File\FileUrlGeneratorInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\node\NodeInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
/**
* News release redirect subscriber.
*/
class RedirectSubscriber implements EventSubscriberInterface {
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* The FileUrlGeneratorInterface service.
*
* @var \Drupal\Core\File\FileUrlGeneratorInterface
*/
protected $fileUrlGenerator;
/**
* DeleteAssets constructor.
*
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
* @param \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator
* The FileUrlGeneratorInterface service.
*/
public function __construct(AccountInterface $current_user,FileUrlGeneratorInterface $file_url_generator) {
$this->currentUser = $current_user;
$this->fileUrlGenerator = $file_url_generator;
}
/**
* {@inheritdoc}
*/
public function checkForRedirection(RequestEvent $event) {
#判断当前访问路由的用户如果不是匿名用户直接返回
if (!$this->currentUser->isAnonymous()) {
return;
}
$attr = $event->getRequest()->attributes;
/**
* @var \Drupal\node\NodeInterface
*/
$node = $attr->get('node');
#从当前路由里面获取node,如果有node,并且node的type是basic,并且这个node已经是发布状态才进行下一步的处理逻辑。
if ($node instanceof NodeInterface && $node->bundle() == 'basic' && $node->isPublished()) {
#如果这个node有field_pdf这个字段,并且他是一个media entity就会获取这个media对应的file文件地址,并从定向到这个file文件地址去
if ($node->hasField('field_pdf') && $media = $node->get('field_pdf')->entity) {
$file = $this->mediaTool->getMediaFile($media);
$event->setResponse(new RedirectResponse($this->fileUrlGenerator->generateAbsoluteString($file->getFileUri())));
}
#如果这个node有field_url 字段,并且field_url字段有值,就会从定向到field_url字段的值上去,这个field_url字段有可能是一个外部的url,比如说是https://www.google.com 所以我们这里需要用Drupal的TrustedRedirectResponse去设置返回的url,如果这个路由不是Drupal内部的路由,用RedirectResponse会抛出一个错误。
elseif ($node->hasField('field_url') && !$node->get('field_url')->isEmpty()) {
$target_url = $node->get('field_url')->uri;
if (!empty($target_url)) {
$event->setResponse(new TrustedRedirectResponse($target_url));
}
}
}
}
#主要是在这里定义我们的时间订阅类型,我们这里注册的时间订阅类型为Request,所以Drupal的请求都会走到我们这里的事件订阅进行处理。***checkForRedirection*** 这个方法代表了我们这个事件订阅具体要处理业务的方法
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = ['checkForRedirection'];
return $events;
}
}
Done
最后通过drush命令清楚drupal缓存 drush cr 然后刷新页面,就能看到神奇的事情发生了!