Drupal 9的设计大量依赖于service。sevices的核心是让依赖的逻辑写在初始化阶段,这样可以让实际逻辑大大简化,并且可维护性更好。所有\Drupal的写法都是Drupal对面向过程写法的兼容,被视为违反设计模式。不确定会不会在后续Drupal版本(例如Drupal 10)里不能用。下面是一个在Form里如何用Drupal 9 service的方式实现\Drupal::configFactory()功能的例子。就单一功能来说,例子的写法似乎更复杂了。但就整个复杂的系统来说,这样做是简化了,当我们熟悉了初始化service的方式,那些初始化的代码基本都是复制粘贴的。
1. FormBase和ControllerBase子类引入service的方法
<?php
namespace Drupal\utility\Form\SystemConsole\ConfigForm;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\utility\System\System;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
final class LoginConfig extends FormBase {
/**
* The config factory object.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory')
);
}/**
* Constructs a ExampleController object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* A configuration factory instance.
*/
public function __construct(ConfigFactoryInterface $configFactory) {
$this->configFactory = $configFactory;
}/**
* {@inheritdoc}
*/
public function getFormId() {
return 'utility_system_login_config';
}/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {$form['user_login_error_limit'] = [
'#type' => 'textfield',
'#title' => '用户登录失败次数限制',
'#description' => '(用户尝试登录失败次数超过限制次数时,将被限制登录)',
'#default_value' => $this->configFactory->getEditable('user.flood')->get('user_limit'),
];$form['save'] = [
'#type' => 'submit',
'#value' => '保存',
];
return $form;
}/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$messenger = $this->messenger();
$user_limit = $form_state->getValue('user_login_error_limit');
$this->configFactory->getEditable('user.flood')->set('user_limit', $user_limit)->save();$messenger->addStatus('保存成功');
}}
事实上,configFactory是FormBase的属性,在FormBase子类里无法再实现,调用$this->configFactory()即可获得该服务引用对象。
2. 定义自己的service
如果我们的类不是FormBase或ControllerBase的子类,而类里面需要调用service。那么我们可以在example.services.yml里声明自己的service。
services:
utility.zip:
class: Drupal\utility\Component\Zip\ZipMarker
arguments: ['@current_user', '@file_system', '@messenger']
然后在构造方法里给依赖的服务初始化:
public function __construct(AccountInterface $currentUser, FileSystemInterface $fileSystem, MessengerInterface $messenger) {
$this->user = $currentUser;
$this->fileSystem = $fileSystem;
$this->messenger = $messenger;
}
调用的时候很方便,连use都不用:
$zipMaker = \Drupal::service('utility.zip');
这里有另外一篇笔记进一步探讨服务、容器、依赖设计模式:https://cto.eguidedog.net/node/1199
参考:
评论