drupal-hooks について
Drupal モジュール開発者向けの Drupal 11 Hook リファレンスです。`src/Hook/` のテスト可能なオブジェクト指向 Hook を優先し、手続き型 Hook やイベントサブスクライバーの使い分けも説明します。
主な機能
- 01属性を使ったオブジェクト指向 Hook の定義
- 02コンストラクターによる依存性注入
- 03Drupal 11.1+ の自動登録
- 04`src/Hook/` 外の Hook の手動登録
- 05Hook とイベントサブスクライバーの比較
活用シーン
- 01Drupal モジュールの新しい Hook の実装
- 02手続き型 Hook のクラスへのリファクタリング
- 03Hook とイベントサブスクライバーの選択
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ edutrul/ drupal-ai --skill drupal-hooksインストール後、Claude Code で/drupal-hooksを入力して読み込まれたか確認します。
同梱ファイルREADME.md
詳細
Drupal Hooks(Drupal 11)
OOP フック(推奨)
| 場所 | src/Hook/MyModuleHooks.php |
| 名前空間 | Drupal\my_module\Hook |
| 自動登録 | Drupal 11.1+(services.yml は不要) |
| DI サポート | コンストラクターインジェクション |
| テスト可能 | はい — 直接インスタンス化し、モックを注入できます |
例(ベストプラクティス)
<?php
namespace Drupal\my_module\Hook;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\node\NodeInterface;
final class MyModuleHooks {
use StringTranslationTrait; // Provides $this->t().
public function __construct(
private readonly AccountProxyInterface $currentUser,
) {}
/**
* Implements hook_form_node_article_form_alter().
*
* Prefer targeted form hooks over generic form_alter — they only fire for
* the specific form ID and avoid unnecessary processing.
*/
#[Hook('form_node_article_form_alter')]
public function formNodeArticleFormAlter(array &$form, FormStateInterface $form_state): void {
$form['title']['#title'] = $this->t('Article title');
}
/**
* Implements hook_form_alter().
*
* Use only when acting on multiple forms or the form ID is unknown at
* development time. Check $form_id explicitly.
*/
#[Hook('form_alter')]
public function formAlter(array &$form, FormStateInterface $form_state, string $form_id): void {
if ($form_id === 'node_page_form') {
$form['title']['#description'] = $this->t('Enter a descriptive page title.');
}
}
#[Hook('node_presave')]
public function nodePresave(NodeInterface $node): void {
if ($node->getType() === 'article') {
// Example: stamp the current user's ID on save.
$node->set('uid', $this->currentUser->id());
}
}
#[Hook('theme')]
public function theme(): array {
return [
'my_template' => [
'variables' => ['content' => NULL],
],
];
}
}
注記: フックが実行されない場合は、名前空間と場所を確認してください。
src/Hook/の外にある OOP フックは、手動でサービス登録する必要があります。
services.yml
| シナリオ | 必要ですか? |
|---|---|
src/Hook/ にあり、名前空間が Drupal\my_module\Hook のクラス | いいえ — 自動登録されます(Drupal 11.1+) |
src/Hook/ の外にあるクラス(カスタムサービスなど) | はい — 手動で登録してください |
登録が必要な場合 — オートワイヤリングにより、型ヒントに基づいてコンストラクターの依存関係が解決されます:
namespace Drupal\my_module\Service;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Session\AccountProxyInterface;
final class MyCustomService {
public function __construct(
private readonly AccountProxyInterface $currentUser,
) {}
#[Hook('form_alter')]
public function formAlter(...): void {
// ...
}
}
services:
Drupal\my_module\Service\MyCustomService:
autowire: true
プロシージャルフック(.module)
my_module_hook_name() の命名規則により自動検出されます。現在も有効ですが、新しいコードでは OOP フックを推奨します。
フックとイベントサブスクライバー
| フックを使用する場合 | イベントサブスクライバーを使用する場合 |
|---|---|
form_alter、エンティティフック、テーマフック | ディスパッチされた Symfony イベントへの反応 |
| Drupal コア/コントリビュートの動作を拡張する | PSR-14/疎結合システム |
| 既存の Drupal API を使用する | 疎結合なロジックを構築する |
src/Hook/の OOP フックは完全にテスト可能です — クラスを直接インスタンス化し、モック化した依存関係を注入してください。
ルール(重要)
- 新しい実装では、必ず
src/Hook/の OOP フックを優先してください - 明示的に依頼されない限り、
.moduleに新しいフックを追加しないでください - プロシージャルフックが存在する場合は、OOP へのリファクタリングを提案してください
コメント
Markdown 対応