Drupal Advent Calendar 2023 の6日目です。
前日の投稿ではウミ菊池さんから非エンジニア視点での Drupal 10.2 変更点ピックアップが紹介されていましたので、本記事ではDrupal 10.2に含まれる開発者向けのアップデート(の中から私が理解できたもの)をいくつか紹介しようと思います。執筆時点の最新バージョンであるDrupal 10.2.0-rc1を参照しています。
新機能
プラグインタイプで、Annotationsの代わりにAttributesが利用できるように
Drupalでは、ブロックやViewsで利用されているプラグインシステムでDoctrine Annotationsが活用されています。PHP 8から言語ネイティブでAttributesがサポートされたことで、Drupal 10.2からAttributesを使用したプラグイン開発ができるようになりました。
Doctrine AnnotationsはDrupal 10中に非推奨となり、Drupal 11で削除される計画です。
AnnotatedClassDiscoveryで独自プラグインタイプを作成している方は、Attributesを使用した実装方法に移行する必要があります。
AnnotatedClassDiscoveryが利用されたプラグインタイプを用いてプラグインを作成している方は、まずプラグインタイプ側でAttributesがサポートされていることを確認し、Attributesを使用した実装方法に移行する必要があります。
Drupal 10.2の時点では、コアではBlockとActionのみがAttributesに対応しています。
コード例
ブロックプラグインタイプを使用してプラグインを作成した例を示します。
Drupal 10.1以前
<?php
namespace Drupal\marucha\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/**
* Provides marucha block.
*
* @Block(
* id = "marucha_block",
* admin_label = @Translation("Marucha Block"),
* )
*/
class MaruchaBlock extends BlockBase {
public function build() {
return [
'#markup' => 'This is marucha block.',
];
}
}
Drupal 10.2以降
<?php
namespace Drupal\marucha\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Block\Attribute\Block;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Provides marucha block.
*/
#[Block(
id: 'marucha_block',
admin_label: new TranslatableMarkup('Marucha Block')
)]
class MaruchaBlock extends BlockBase {
public function build() {
return [
'#markup' => 'This is marucha block.',
];
}
}
差分
参照
- https://www.drupal.org/node/3395582
- https://www.drupal.org/docs/drupal-apis/plugin-api/attribute-based-plugins
- https://speakerdeck.com/acquiajp/drupal-moziyurukai-fa-ru-men-jiang-zuo-di-7hui-puraguin
イベントサブスクライバでSymfonyのautoconfigurationが利用可能に
イベントをサブスクライブする場合、モジュールの *.service.yml ファイルにサブスクライバを登録します。Drupal 10.2からは、service.ymlの _defaults
キー内に autoconfigure: true
を指定することで個別にタグをつける必要がなくなりました。
コード例
Drupal 10.1以前
services:
marucha.config_subscriber:
class: '\Drupal\marucha\EventSubscriber\ConfigSubscriber'
tags:
- { name: 'event_subscriber' }
Drupal 10.2以降
services:
_defaults:
autoconfigure: true
marucha.config_subscriber:
class: '\Drupal\marucha\EventSubscriber\ConfigSubscriber'
差分
参照
- https://www.drupal.org/node/3357408
- https://speakerdeck.com/acquiajp/drupal-moziyurukai-fa-ru-men-jiang-zuo-di-6hui-ibento
ControllerBaseクラスでDIする際にcreate()メソッドが不要に
コントローラー、フォーム、ブロックなどのクラスでサービスを注入する場合、create()ファクトリメソッドをオーバーライドすることでサービスを読み込むことができます。
Drupal 10.2ではControllerBaseクラスにAutowireTraitが実装され、サービスを読み込むためであればcreate()メソッドの実装は不要になりました。1
コード例
Drupal 10.1以前
<?php
namespace Drupal\marucha\Controller;
use Drupal\Component\Datetime\Time;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
class MaruchaController extends ControllerBase {
protected $time;
public function __construct(Time $time) {
$this->time = $time;
}
public static function create(ContainerInterface $container) {
return new static(
$container->get('datetime.time')
);
}
# 省略
Drupal 10.2以降
<?php
namespace Drupal\marucha\Controller;
use Drupal\Component\Datetime\Time;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
class MaruchaController extends ControllerBase {
protected $time;
public function __construct(
#[Autowire(service: 'datetime.time')]
Time $time
) {
$this->time = $time;
}
# 省略
差分
参照
- https://www.drupal.org/node/3395716
- https://www.drupal.org/docs/drupal-apis/services-and-dependency-injection/dependency-injection-for-a-form
- https://speakerdeck.com/acquiajp/drupal-moziyurukai-fa-ru-men-jiang-zuo-di-5hui-sabisu
#config_targetプロパティがConfigFormBaseクラスに追加
以下のように、スキーマファイルで constraints
キーを使用することで各構成値に制約を設定できます。
marucha.settings:
type: config_object
label: 'Marucha settings'
mapping:
name:
type: label
label: 'Name'
constraints:
NotBlank:
message: "入力してください!(スキーマファイル側で制御)"
しかし、フォームではこの制約の定義を読み込むことは出来ず、validateForm()メソッドで同じようなロジックを記述する必要がありました。
Drupal 10.2から、ConfigFormBaseクラスに #config_target
プロパティが実装され、これを使用することでスキーマファイルに定義された制約で検証を行うことができるようになりました。
コード例
Drupal 10.1以前
<?php
namespace Drupal\marucha\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
class MaruchaConfigForm extends ConfigFormBase {
public function getFormId() {
return 'marucha_config_form';
}
protected function getEditableConfigNames() {
return ['marucha.settings'];
}
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('marucha.settings');
$form['name'] = [
'#type' => 'textfield',
'#title' => $this->t('Name'),
'#default_value' => $config->get('name'),
];
return parent::buildForm($form, $form_state);
}
public function validateForm(array &$form, FormStateInterface $form_state) {
if (!$form_state->getValue('name')) {
$form_state->setErrorByName('name', '入力してください!(validateFormメソッドで制御)');
}
}
# 省略
Drupal 10.2以降
<?php
namespace Drupal\marucha\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
class MaruchaConfigForm extends ConfigFormBase {
public function getFormId() {
return 'marucha_config_form';
}
protected function getEditableConfigNames() {
return ['marucha.settings'];
}
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('marucha.settings');
$form['name'] = [
'#type' => 'textfield',
'#title' => $this->t('Name'),
'#default_value' => $config->get('name'),
'#config_target' => 'marucha.settings:name',
];
return parent::buildForm($form, $form_state);
}
# 省略
差分
参照
- https://www.drupal.org/node/3373502
- https://youtu.be/Dnxp3aBPGhs?si=ltNuSiohmaODXfn8&t=296
- https://speakerdeck.com/acquiajp/drupal-moziyurukai-fa-ru-men-jiang-zuo-di-9hui-gou-cheng
まとめ
私が触ったことがあるAPIを中心に新機能を紹介しました。コード例はリポジトリに公開しました。
-
フォームやブロックは・・・? ↩