Drupalでカスタムモジュールを作ってみよう

この記事ではDrupalでカスタムモジュールを作成するやり方をご紹介します。

# Drupalを使ってWEBサイトを作る流れ
***1. コアモジュールで機能を実現する***
Drupalインストール時に用意されているモジュールで実現できないか検討します。

***2. コアモジュールでできないことをコントリビュートモジュールで実現する***
Drupal.orgで公開されているコントリビュートモジュールで実現できないか検討します。

***3. コントリビュートモジュールで実現できない機能をカスタムモジュールで実現する***
ここまで検討して実現できていない場合は独自の機能である可能性が高いです。
そのためルーティングやテンプレートを活用してカスタムモジュールで機能を実現します。

<br>

まずはコアモジュールやコントリビュートモジュールで実現できないか？という観点で検討します。
なぜならばコアモジュールやコントリビュートモジュールで実現できれば、
インストールと設定で作業が済むため圧倒的にコストを抑えることができるからです。

ですがそのサイト独自の機能であれば出回っている可能性が非常に高いです。
そのような場合はカスタムモジュールを作成して機能を実現します。

今回はサンプルのモジュールを用いてカスタムモジュールの作成方法をご紹介していきます。

# 今回作成するモジュール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/25fdb318-7a54-adc6-a300-0b72d53d0e4a.png)
画面にアクセスすると文字列を表示するページを作ってみます。
文字列はプログラムで指定した値を表示します。

# カスタムモジュールを作成する
## モジュール用のフォルダを作成する
web/moudles配下にcustomフォルダを作ります。
```
mkdir custom
```

さらにその配下にカスタムモジュール用のフォルダを作ります。
このフォルダはカスタムモジュール1つに対して作成し、フォルダ名はカスタムモジュールのマシン名にします。
今回はhello_moduleというマシン名で作成します。
```
mkdir hello_module
```

## 設定ファイルを作成する
設定ファイルはそのモジュールの名前や説明、対応するコアバージョンを定義するファイルです。
先ほど作成したweb/modules/custom/hello_moduleにhello_module.info.ymlを作成します。
```
touch hello_module.info.yml
```

:::note info
ファイル名のhello_moduleの部分は作成するモジュールのマシン名に置き換えてください。
:::

今回は設定ファイルは以下のように設定します。

```
name: HelloWorld
type: module
description: '画面に「Hello, World!」を表示します。'
package: Custom
core_version_requirement: ^9 || ^10
```
今回設定ファイルに定義した項目はそれぞれ以下の通りです。

:::note info
name : モジュールの名前です。管理画面に表示されます。
type : モジュールの場合はmoduleで固定です。
description : モジュールの説明です。管理画面に表示されます。
package : Customというパッケージで管理することを表しています。無くても問題ないです。
core version requirement : どのコアバージョンで動作するかを指定します。
:::

これでモジュールとして必要最低限作成できました。
この状態でインストールは可能ですがまだ何も機能がないのでここからカスタマイズしていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/0463ef25-b9a2-f8a6-2469-170b8c76a4a0.png)

## ルーティングを作成する
ルーティングとは***URLとそのURLにアクセスしたときに動作するプログラムを紐づけること***です。
hello_moduleでは/hello_worldというURLにアクセスしたら文字列を表示することにします。

hello_module.info.ymlと同階層にhello_module.routing.ymlを作成します。
以下の内容を記載します。

```
hello_module.content:
  path: '/helloworld'
  defaults:
    _controller: '\Drupal\hello_module\Controller\HelloWorldController::display'
    _title: 'Hello, World!'
  requirements:
    _permission: 'access content'
```

:::note info
今回定義した項目はそれぞれ以下の通りです。

path : ルーティングのURL
controller : ルーティングで使用するプログラム（コントローラー）
title : ページのタイトル
permission : どの権限を持つユーザーにアクセスできるようにするか
　※’access content’を指定しておけばどのユーザーもアクセスできます。
:::

次にルーティングで指定したプログラムを作成します（controllerに指定したプログラム）。
hello_module.info.ymlと同階層にsrcフォルダを、
さらに配下にControllerフォルダを、
そしてその配下にHelloWorldController.phpを作成します。

```
mkdir src
mkdir Controller
touch HelloWorldController.php
```

HelloWorldController.phpは以下のソースコードです。
```HelloWorldController.php
<?php
namespace Drupal\hello_module\Controller;

use Drupal\Core\Controller\ControllerBase;

class HelloWorldController extends ControllerBase {

    public function display() {
        $arr = [
            '#theme' => 'custom_template',
            '#text' => 'Test',
        ];
        return $arr;
    }

}
```

:::note info
ここではcustom_templateと呼ばれるレンダリングファイル（テンプレート）を使用し、
textという変数に「Text」という文字列を格納してテンプレートに渡しています。
:::

次にルーティングファイルのテンプレートを作成します。
hello_module.info.ymlと同階層にtemplateフォルダを、
その配下にcustom-template.html.twigを作成します。
```
mkdir template
touch custom-template.html.twig
```

custom-template.html.twigは以下のソースコードです。
```custom-template.html.twig
<p>Hello, World!</p>
<p> Welcome to our {{ text }} site</p>
```

:::note info
ロジックはコントローラーで作り、ビューはテンプレートで作りました。
このように役割を分けると後々の保守もしやすくなります。
:::

## モジュールフックを作成する
最後にモジュール用のフックを作成するためのファイルを作ります。
hello_module.info.ymlと同階層でhello_module.moduleを作成します。
```
touch hello_module.module
```

hello_module.moduleの内容は以下の通りです。
```hello_module.module
<?php

/**
* Implementation of hook_theme()
*/

function hello_module_theme($existing, $type, $theme, $path) {
    
    $arr = [
        'custom_template' => [
            'variables' => ['text' => ""],
        ],
    ];

    return $arr;
}
```

:::note info
hook_themeをオーバーライドし、
custom_templateでtextという変数を使えるように設定しています。
:::

ここまででモジュールが作成できました。
最後にモジュールをインストールします。

## モジュールをインストールする
管理画面の機能拡張にアクセスします。
フィルターでhello_moduleを検索し、チェックを入れてインストールを実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/7469ca8d-ead4-9d3c-aebc-8057854b2299.png)

以下のようなメッセージが出ればインストール成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/20d02a9d-10b1-961f-cafb-9e4bf82b5de0.png)

確認のため/helloworldにアクセスしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/29d18463-dbd2-0581-774b-ce8d087cdae7.png)
無事文字列を表示することができました！
テンプレート上でtestという変数に入っていた文字列も表示できています。

以上がカスタムモジュールを作成するまでの流れです。

# さいごに
今回はDrupalでカスタムモジュールを作成する方法をご紹介しました。

もしコアモジュールでもコントリビュートモジュールでも実現できない機能があれば
今回ご紹介した内容を参考にぜひモジュールを作ってみてください。

この記事ではページとして機能を提供するモジュールを作成しましたが、
実際にはブロックやAPIとして作成することもできます。
カスタムモジュールについてもっと知りたいという方は以下の記事が参考になるかと思います。
ぜひ目を通してみてください。

https://www.acquia.com/jp/blog/introduction-to-examples-for-developers-module