Drupalでカスタムモジュールを作るときはExamplesモジュールを参考にしよう

対象読者

Drupalで初めてカスタムモジュールを作る開発者の方

はじめに

Drupalでウェブサイト・ウェブアプリを作るときのステップは、(1)コアモジュールにある機能をできるだけ使う、(2)コアモジュールで足りない機能はコントリビュートモジュールを探して使う、(3)コントリビュートモジュールで足りない機能のみをカスタムモジュールを利用する、となります。

シンプルなサイトであれば(2)のコントリビュートモジュールまでで作れることもありますが、特殊な業務要件に対応する場合などは自分でモジュールを作ることも必要です。しかし、カスタムモジュールの作成には、ベストプラクティス知識がないと、シンプルな機能追加に多大な工数が無駄にかかってしまう恐れがあります。

そのような無駄な工数や車輪の再発明を避けるために、開発者がモジュール開発を行う際どのようなコードを書けば良いのかの例を示すDrupalのコントリビュートモジュールとして、Examples for Developersモジュールというのもがあります。

https://www.drupal.org/project/examples

Examples for Developersモジュールとは

Examples for Developersモジュールとは、オープンソースでダウンロードできるDrupalのコントリビュートモジュールの一つですが、このモジュールは、Drupalサイトに新しい機能を与えるものではなく、開発者がコードを読んで、モジュール開発のベストプラクティスを学ぶためにあります。

この記事ではExamples for Developersモジュールにある様々な機能を一つづつ紹介します。初めてカスタムモジュールを作る開発者の方が参考にできるExamplesモジュールを見つける一助になれば幸いです。

なお、このExamples for Developersモジュールには、管理UIから設定できる機能をあえてコードで書いているが多くあります。コントリビュートモジュールや複数のプロジェクトで汎用的に使えるモジュールを作るのでなければ、なるべく可能なものは管理UIを使うのがお勧めです。

各Examplesモジュールの紹介

各ExampleモジュールはExamples for Developersモジュールのルートディレクトリ内の/modulesにあります。.modulesファイルには各機能の説明があるので参考にしてください。

Ajax Example

Ajaxフォームを作成するコードを紹介しています。あるフィールドの値に応じて別フィールドのドロップダウンの選択肢が変わるフォーム、ページリロードなしにフォーム送信するボタンの実装方法、多段階入力フォーム等の構築方法が学べます。

Batch Example

バッチ処理を行う定義するコードを紹介しています。モジュールを有効化すると送信時にバッチが起動するフォームが表示されるので、コードと合わせて実際の挙動を確認できます。

Block Example

モジュールでブロックを定義するコードを紹介しています。ブロックを作成するために必要な最低限のコードが記述されている「Empty Example Block」、ブロックのタイトルを自動的に大文字にする(=内部処理でアウトプットを変更する)「Example Upper Case Block」、ブロックからのアウトプットをフォームから入力できる「Example Configurable Block」が含まれています。

Cache Example

Drupalのキャッシュ機能の使い方を紹介するモジュールです。/coreディレクトリ内にあるファイル数を数える処理を実際にキャッシュさせ、有効期限の設定とパージを行う方法が記述されています。

Config Entity Example

コンフィグエンティティ(設定データ)の管理方法を紹介するモジュールです。新規にコンフィグエンティティをモデルとして定義し、追加・削除・編集するフォーム、一覧表示するページ、モジュールのインストール時に初期値を設定するコードが記述されています。

Content Entity Example

Entity APIを使ったコンテントエンティティ(コンテンツデータ)の管理方法を紹介するモジュールです。NodeやUserのような主にエンドユーザーが追加可能なデータを定義し、設定、表示・追加・編集・削除するコードが記述されています。

Cron Example

DrupalにCronジョブを設定するHookのhook_cron()の使い方を紹介しています。Cronを登録する際に必要な設定(処理内容、インターバル)が記述されています。

DBTNG Example

DBTNG(Database: The Next Generation)と呼ばれるDatabase APIの利用方法を紹介しています。インストール時にスキーマを定義する方法とデータベースを接続し、データを表示・追加・編集・削除する方法を記述しています。

Email Example

Drupalのmail APIを利用し、簡単なコンタクトフォームに入力された内容をメール送信する方法と、他のモジュールから送信されるメール内容を上書きする方法を記述しています。

Events Example

旧来からあるHook機能に取って代わるEvent機能を紹介するモジュールです。Event機能を使うことで、元モジュールのコードを変更することなく処理を上書きできます。この例ではEventのsubscribe(Eventの発生を監視する)方法とdispatch(Eventを発行する)方法が記述されています。

Field Example

Field APIを利用したフィールド管理機能を紹介しています。フィールドタイプの定義、スキーマの定義、フィールドウィジェットの定義(カラーピッカーやテキスト入力フィールド等)、フィールドフォーマッター(値のアウトプット方法)の記述方法が学べます。

Field Permission Example

フィールドへのアクセスを制限する機能を紹介します。閲覧の制限と編集の制限に分かれており、権限のページからどの役割がアクセス可能なのかを設定できるようになっています。

File Example

現行最新版(3.x)では、コード例がありませんのでスキップです。

Form API Example

Drupal上でフォームを作るためのForm APIの使い方を紹介します。\Drupal\Core\Form\FormBase(コンテンツ作成フォーム)もしくは\Drupal\Core\Form\ConfigFormBase(設定エンティティフォーム)を継承して作成する方法と、フォームを表示するページの定義を行います。

また、以下のフォームの作成方法を記述しています。

  • Simple Form: 最低5文字入力が必要なフォーム(バリデーションがある)
  • Multistep form: 多段階フォーム
  • Common input elements: 一般的な入力ウィジェットが網羅されているフォーム
  • Build form demo: Ajaxでフォームをrebuildできるフォーム
  • Container elements: Detail(クリックするとフォームが表示される)、fieldset、container要素の例
  • Form state building: フォームの値に応じてフォーム表示を切り替える機能
  • Vertical tab elements: 縦に並ぶタブにフォームを表示
  • Ajax color form: Ajaxでフィールドの値に応じて別フィールドをロードする例
  • Add-more button: Ajaxで値を追加するフォーム
  • Modal form: Modal上にフォームを表示する例

Hooks Example

Hookを実装する例です。将来上述のイベントが取って代わる機能ですが、DrupalにはまだHook機能が残っています。Hookを命名、実装(=既存のHookを利用)、定義する例が記述されています。

JS Example

DrupalにおけるJSの扱いを紹介します。アコーディオンUIを表示する機能の例と、コンテンツに「Weight(重さ)」を設定し、表示順を変更する例があります。後者ではdrupalSettingsを利用して、PHPで保持していた値をJSに渡すことができるというのがポイントです。

Menu Example

メニューリンクを管理する機能を紹介しています。Drupal 7とは異なりDrupal 8/9ではSymfonyフレームワークのRoutingシステムがベースになっています。この例ではrouting.ymlにパスを定義し、変数が必要なcontrollerをで処理を行うコードが記述されています。

Node Type Example

モジュールでコンテンツタイプ(Nodeの種類)を作成する方法を紹介しています。有効化すると2種類のコンテンツタイプが作成されます。一つは管理画面から削除可能で、もう一つはモジュールを無効化する以外には削除できません。削除の可否はhook_installで設定します。

Page Example

任意のURLからアクセスできるページを作成する例を紹介しています。Menu Exampleよりシンプルにrouting.ymlでのURLからの変数の取得設定とcontrollerによるページのレンダリング処理を読むことができます。

Pager Example

ページャーを使い、Nodeの一覧を10件ずつ表示する例を記述しています。

PHPUNIT Example

PHPUnitを利用したテストの書き方を紹介しています。テストコードはモジュール以下/tests/srcに置かれています。

Plugin Type Example

プラグインと呼ばれる機能を紹介しています。アノテーションを使い、予め定義されたクラスを効率よく継承することができます。手順は(1)アノテーションの定義(2)プラグインのInterfaceを定義(3)Plugin Managerを定義(4)任意でBaseクラスを作成、です。

この例はプラグインを自分で作成する例で難易度が高いですが、ブロックやViewsの拡張のために、既に定義されているプラグインをアノテーションで拡張することは多く、裏側の処理を知っておく意味で理解しておくと良いコードです。

Queue Example

FIFO(先入れ先出し)方式で処理するQueueの例です。Queueアイテムの作成(Create)、次のアイテムの要求(Claim)、スキップ(Release)、削除(delete)のコンセプトを紹介しています。

Render Example

Render APIの利用例を紹介しています。Drupalでは配列として持っているデータを最終的にレンダリングすることでHTMLとしてアウトプットします。これにより、モジュールやテーマによってアウトプットするデータをギリギリまで処理可能なようにしています。この例ではレンダリング配列とそれがどのようにアウトプットされるかをページとフォームの両方で紹介しています。

REST Example

REST APIの動作を紹介しています。Drupal側でnodeの一覧をJSON形式で表示し、別のアプリケーションが取得・表示するためのendpointを作成する方法を記述しています。

Session Example

Sessionを扱う方法を紹介しています。フォームに入力した情報をSessionで保持し、ページで読み出しアウトプットする例です。

Stream Wrapper Example

PHPのStream Wrapperを利用してファイルを読み書きする方法を紹介しています。

Tabledrag Example

ドラッグしてテーブル行の順番を変更するUIを実装する方法を紹介しています。行に親子関係を付与したり、親としてのみ使える行を設定したりすることができます。

Tablesort Example

テーブルの行をソートするUIを実装する方法を紹介しています。Drupal\Core\Database\Query\TableSortExtenderクラスを活用します。

Testing Example

SimpletestというDrupal 7からあるテストツールを利用する方法の紹介です。これから新しくテストを各場合には上述のPHPUnitが良いでしょう。

Theming Example

モジュールからアウトプットしたHTMLコンポーネントに対してCSSやテンプレートを適用する例です。モジュールが生成したページ、リスト要素、フォームに対して、スタイルやTwigテンプレートを当てはめる方法が記述されています。

Tour Example

サイト訪問者に対して、ウェブサイトのUIを解説するTour機能の実装例です。ymlファイルに記述するだけでシンプルに実装できます。

終わりに

この記事ではDrupalのコントリビュートモジュールであるExamples for Developersを紹介しました。Drupalはカスタマイズの柔軟性が高い分、同じ機能に対して様々な実装方法が存在するため、このモジュールを参考に一番効率の良い手法を採用していただければ幸いです。

また、繰り返しですが、これらの例は管理UIから行える機能をコードで書いているものが多くあります。コードを書く前にコア機能やコントリビュートモジュールで対応できないか、は常に意識すると良いと思います。

岸 俊兵

Solutions Architect Acquia

カナダ・イエローナイフでウェブ開発者として勤務していた際、エンタープライズ向けオープンソースCMSのDrupalによる開発に従事。帰国後、Drupalのヘビーユーザーであるジョンソン・エンド・ジョンソン株式会社の社内SEを経て、2019年1月よりアクイアジャパンのソリューションアーキテクト。Drupalを中心としたデジタル体験プラットフォームであるアクイア製品の提案活動が主業務。