Hux

PHP 8 attributeを使用して.moduleファイルなしでhook実装を可能にし、完全なdependency injectionをサポートします。

hux
453 sites
42
drupal.org

インストール

Drupal 11, 10 v1.6.1
composer require 'drupal/hux:^1.6'

概要

Huxは、Drupalのhook実装方法を革新する開発者向けモジュールです。.moduleファイル内の従来の手続き型関数を使用する代わりに、クラスベースのserviceでPHP 8.0以上のattributeを使用してhookを実装できます。

このアプローチには、オートワイヤリングまたはContainerInjectionInterfaceによる完全なdependency injectionサポート、モジュールごとの複数hook実装、他のモジュールからのhookの置換やオーバーライド機能、より明確な関心の分離など、いくつかの重要な利点があります。hookクラスは任意のモジュールのsrc/Hooksディレクトリで自動的に検出され、最初のcacheクリアのみが必要です。

Huxは、従来の手続き型hookとhook_event_dispatcherのような完全なイベント駆動アーキテクチャの中間に位置し、慣れ親しんだhookのシグネチャとパターンを維持しながら、dependency injectionとクラスベースのロジックの利点を提供します。

Features

  • PHP 8 attribute(#[Hook]、#[Alter])を使用して.moduleファイルなしでhookを実装
  • オートワイヤリングとContainerInjectionInterfaceによる完全なdependency injectionサポート
  • 優先度順序付けによるモジュールごとの複数hook実装
  • #[ReplaceOriginalHook]を使用して他のモジュールのhookを置換またはオーバーライド
  • #[OriginalInvoker]パラメータattributeを使用して元のhook実装をcallableとしてアクセス
  • 繰り返し可能なattributeを使用して単一メソッドで複数hookをリッスン
  • service登録なしでsrc/Hooks名前空間内のhookクラスを自動検出
  • hookを実装する際に別のモジュールとして偽装
  • hook検出を事前cacheする本番環境向けの最適化モード
  • 既存のhookクラスに新しいhookを追加する際にcacheクリアが不要

Use Cases

dependency injectionを使用したentityアクセスhookの実装

現在のユーザー、entity type manager、またはカスタムserviceなどの注入されたserviceにアクセスしながらentityアクセスロジックを実装するhookクラスを作成します。オートワイヤリング経由で依存関係を受け取るコンストラクタを持つクラスをsrc/Hooks/MyModuleHooks.phpに配置します。

コントリビュートモジュールのhook実装の置換

#[ReplaceOriginalHook]を使用して、別のモジュールがhookを実装する方法を完全にオーバーライドします。例えば、media_entity_access()を独自のロジックで置き換え、オプションで#[OriginalInvoker]経由で元の実装を呼び出すことができます。

優先度付きの複数hook実装

単一モジュール内で同じhookを複数回実装し、それぞれに異なる優先度を設定します。優先度の高いhookが最初に実行され、事前検証、メイン処理、後処理などの階層化されたロジックが可能になります。

単一メソッドで複数の関連hookをリッスン

繰り返し可能なattributeを使用して、entity_insert、entity_update、entity_deleteなどの複数hookに1つのメソッドで応答し、統一されたentityライフサイクル処理を実現します。

大規模モジュールでの明確な関心の分離

hookを機能に基づいて複数のクラス(例:AccessHooks.php、FormHooks.php、EntityHooks.php)に整理し、src/Hooksディレクトリ内に配置すると、すべて自動的に検出されます。

モック依存関係によるhookのテスト

hook実装はコンストラクタインジェクションを持つ通常のクラスメソッドであるため、コンストラクタ経由で依存関係をモックすることで簡単にユニットテストできます。

Tips

  • 自動検出のためにhookクラスをモジュールのsrc/Hooks/ディレクトリに配置してください - service登録は不要です
  • hookクラスを最初に作成するときのみcacheをクリアしてください。既存クラスに追加された新しいhookは自動的に検出されます
  • 本番環境では最適化モード(parameters.hux.optimize: true)を使用してパフォーマンスを向上させてください
  • オートワイヤリングできないserviceにはContainerInjectionInterfaceを実装してください
  • 同じhookの複数実装の実行順序を制御する必要がある場合はpriorityパラメータを使用してください
  • #[Hook]のmoduleNameパラメータを使用すると、別のモジュールから来たかのようにhookを実装できます
  • #[ReplaceOriginalHook]の非推奨のoriginalInvokerパラメータではなく、パラメータattributeとして#[OriginalInvoker]を使用してください
  • hook_themeとhook_module_implements_alterは、Drupal Coreがそれらを呼び出す方法の関係でサポートされていません

Technical Details

Hooks 2
任意のDrupal hook

Huxは#[Hook] attributeを使用して任意のDrupal hookを実装できますが、hook_themeは呼び出し方法の関係でサポートされていません。

任意のDrupal alter

Huxは#[Alter] attributeを使用して任意のDrupal alter hookを実装できますが、hook_module_implements_alterは除きます。

Troubleshooting 5
hookが呼び出されない

「drush cr」でDrupal cacheをクリアしてください。hookクラスが正しい名前空間Drupal\your_module\Hooks\ClassNameでsrc/Hooksディレクトリにあることを確認してください。クラスに少なくとも1つの#[Hook]または#[Alter] attributeを持つメソッドがあることを確認してください。

オートワイヤリング経由でserviceを注入できない

一部のserviceはオートワイヤリングできません。hookクラスにContainerInjectionInterfaceを実装し、create()静的メソッド経由でserviceを手動で注入してください。

hook_theme実装が機能しない

hook_themeはDrupal CoreがModuleHandler経由で呼び出さないため、Huxではサポートされていません。hook_themeには従来の.moduleファイルアプローチを使用してください。

本番環境でのパフォーマンスの問題

services.ymlファイルで「parameters.hux.optimize: true」を設定して最適化モードを有効にしてください。これにより、コンテナコンパイル時にhook検出が事前cacheされます。

最適化モードに関するランタイム要件の警告

これは開発環境では予想されることです。本番環境では最適化モードを有効にするか、hookを実行時に検出したい開発環境にいる場合は警告を無視してください。

Security Notes 2
  • HuxはDrupal Coreのmodule_handler serviceをデコレートし、すべてのhook呼び出しをインターセプトします。有効なすべてのモジュールが任意のhookを実装または置換できるため、信頼できることを確認してください。
  • #[ReplaceOriginalHook]を使用する際は、適切な再実装なしに他のモジュールからのセキュリティ上重要なhookを誤って無効にしないように注意してください。