Drupal 8 モジュール開発の基本

Drupal 8でモジュールを自作

本格的なサイトの開発ではカスタムフォームとデータベースを繋ぐなど、自前でモジュールを作る必要に迫られる。WordPressに比べて自由度が高いので、モジュールを開発できればコンテンツのポータルとしてではなく、強力なウェブフレームワークとして使えるので、そのための方法を記載します。

まず迷うのが、特定のコードがDrupal特有の記述ルールでそうなっているのか、他所のクラスから継承しているものなのか、ライブラリからインポートして使っているのかが一目でわからないことです。Drupal流の記述はその都度わかるように記載しています。

前提

ある程度PHPが書ける
HTMLとかCSSとかわかる
Drupal 8をインストールしてある

開発したモジュールを置くディレクトリ

<drupalインストールディレクトリ>/modules
この直下に2つのディレクトリを作ることが推奨されている。
   ※drupal 7 ではsites/<自分のサイトディレクトリ>/modulesだったので注意!

作る2つのディレクトリ

contribとcustom

contribにはネットからダウンロードして来たモジュールを入れる
customに自分の書いたモジュールを入れる

datemakiというモジュールを作る

<drupalインストールディレクトリ>/modules/custom/にdatemakiという名前のディレクトリを作成する。

モジュールを構成する最低条件

1. モジュールのディレクトリ
2. xxxxx.info.ymlというファイルの存在

<モジュール名>.info.ymlというファイルを作成する。モジュールのディレクトリの直下に置きます。中身はこのような感じです。

name: "Datemaki"
description: "伊達巻に関するモジュールです"
type: module
core: 8.x
name: "文字列なら何でも良い、普通はモジュール名の英語表記"
description: "管理画面に出て来る説明"
type: module (これはこのまま、クオートなしで)
core: 8.x (これはこのまま、クオートなしで)
   ※ymlとは「ヤムル」と読みます。
   ※ymlではタブを使わず、スペースでインデントします。

これでモジュールとしてリストに表示されます。

何か表示させてみる

これだけだと何も起こらないので何かを表示させてみましょう。何か単純な文字列(例えばHello World)を表示させたいと思ったら、必要なことは以下の通りです。

1. srcディクレトリの作成
2. src/Controllerディレクトリの作成
3. XxxxxController.phpの作成
4. 
xxxxx.routing.ymlの作成

まずはモジュールフォルダの直下に1つのディクレトリ「src」を作成します。その後作ったばかりのsrcの直下に「Controller」というディクレトリを作成します。これらのディレクトリ名はDrupal流、Drupal 8のルールで決まっているので変えてはいけません。Controllerは大文字のCで始まるので注意します。

XxxxxController.phpのXxxxxにはモジュール名が入ります。今回の例ではDatemakiController.phpとなります。
DatemakiController.phpの中身はこんな感じです。

<?php

namespace Drupal\datemaki\Controller;

use Drupal\Core\Controller\ControllerBase;
/**
 * This is my datemaki controller.
 */
class DatemakiController {

  public function showZairyoList() {

    $zairyoArray = [
      ['name' => '卵'],
      ['name' => '塩'],
      ['name' => '砂糖'],
      ['name' => 'はんぺん'],
      ['name' => 'サラダ油'],
    ];

    $output = '';
    foreach ($zairyoArray as $zairyo) {
      $output .= '<li>' . $zairyo['name'] . '</li>';
    }

    return [
      '#type' => 'markup',
      '#markup' => '<ol>' . $output . '</ol>',
    ];

  }
}

namespaceを設定し、ControllerBaseというDrupalの機能を使えるようにuseします。

namespace: Drupal\<モジュールディレクトリ名>\Controller;
use Drupal\Core\Controller\ControllerBase;

useはjavaで言えばimportのようなものです。

class名はファイル名と同じにします。

 public function showZairyoList() {
    $zairyoArray = [
      ['name' => '卵'],
      ['name' => '塩'],
      ['name' => '砂糖'],
      ['name' => 'はんぺん'],
      ['name' => 'サラダ油'],
    ];

    $output = '';
    foreach ($zairyoArray as $zairyo) {
      $output .= '<li>' . $zairyo['name'] . '</li>';
    }

ここのパートは何でもいいのですが、最後にブラウザに表示するためのHTMLコードになるようにしています。

    return [
      '#type' => 'markup',
      '#markup' => '<ol>' . $output . '</ol>',
    ];

ここがDrupal流の書き方です。リターンする配列の中に、'#type' => 'markup'という#typeがあればHTMLを返すという合図になります。

同じ配列で、'#markup' => の値はHTMLタグとしてブラウザに返すことになります。

ルーティングファイルの作成

4. xxxxx.routing.ymlの作成というのが上にあります。モジュールのディレクトリの直下(datemaki.info.ymlを置いた場所)にdatemaki.routing.ymlというファイルを作成します。中身は以下の通り。

datemaki.showZairyoList:
  path: '/zairyo-list'
  defaults:
    _controller: '\Drupal\datemaki\Controller\DatemakiController::showZairyoList'
    _title: '伊達巻の材料'
  requirements:
    _permission: 'access content'

    ※ _controllerのパスは「\Drupal」とバックスラッシュで始まりますので注意してください。

datemaki.showZairyoList:
モジュールディレクトリ名.ブラウザでアクセスしたい関数名
でスタートしています。先ほどのControllerの中にこの関数がありますね。

path: はウェブサイトのURLからアクセスする相対パスを自由に設定します。この例だと、http://www.localhost.com/zairyo-list でアクセスするということです。

defaults:
    _controller: '\Drupal\datemaki\Controller\DatemakiController::showZairyoList'
    _title: '伊達巻の材料'

defaults: の下に子要素が2つあります。
  _controller: には
\Drupal\<モジュールディレクトリ名>\Controller\XxxxxxController
でコントローラーを指定し、
XxxxxxController::<関数名>という書式になります。関数名は1行目に書いたブラウザでアクセスしたい関数名
と同じになるはずです。

  _title: にクオートで入れた文字は、<title>タグの中に入り、<h1>でページにも表示されるようになります。(使用しているテーマによっては異なる)

  requirements:
    _permission: 'access content'

requirements: の子要素の_permissionはDrupal流の権限の制御機構です。ここは適当な文字を入れてはいけません

access contentというのはDrupalでページにアクセスできるという、誰でも持っている特別な権限です。

この_permissionの部分に使用できる文字列には決まりがあります。
サイトのURL/admin/people/permissions を開くと書いてある文字をここに記述します。するとそれが意味する権限の人だけがこのpathにアクセルできます。
 ※ access contentは特別なのでこのリストには載っていません。

モジュールのインストール

まだであればモジュールをインストールしておきます。ここまでの記述に不備があれば、ここでエラーが出ます。エラーを解決しましょう。


アクセスしてみる

.routing.ymlでpathに記述したURIにブラウザでアクセスします。
http://localhost/zairyo-list

DatemakiController.phpの関数showZairyoListでリターンされているHTMLのコードが表示部分に書き出されているのがわかります。

HTMLをテンプレートに切り分ける

上記の方法ではHTMLの書き出し部分をハードコードしているので、メンテナンス性に欠けます。この部分をテンプレートに分けましょう。

1. <モジュールディレクトリ名>.moduleというファイルの作成
2. templatesというディレクトリの作成
3. templatesの中にxxxx.html.twigというファイルの作成
4. コントローラーの修正

まずモジュールの直下にdatemaki.moduleというファイルを作成する。中身はこのように。

<?php

function datemaki_theme($existing, $type, $theme, $path) {

  return [
    'zairyo-list' => [
      'variables' => ['items' => [], 'title' => ''],
    ]
  ];
}

<モジュールディレクトリ名>_themeというのはDrupal流の特別な書き方です。引数もこのまま使います。

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Render%21theme.api.php/function/hook_theme/8.2.x
などのドキュメントをみると詳しく書いてあります。

この部分にその引数が載っています。
hook_themeという関数名があります。このhookというのもDrupal流の書き方です。hookを自分のモジュール名に置き換えて使います。ですから

function hook_theme($existing, $type, $theme, $path) {

が、自分のモジュールで使う時には、

function datemaki_theme($existing, $type, $theme, $path) {

になっています。こういうものをDrupalでは「hook(フック)」と呼びます。

hookの返り値

  return [
    'zairyo-list' => [
      'variables' => ['items' => [], 'title' => ''],
    ]
  ];

配列になっています。zairyo-listの部分は自分で決めています。その子要素のキーである「variables」というのはDrupal流の返り値です。その中身のitemsという配列のそのままにします。
titleは<title>タグの中身になります。titleも変えないようにします。

テンプレートの作成

2. templatesというディレクトリの作成
3. templatesの中にxxxx.html.twigというファイルの作成

この手順に移ります。モジュールの直下にtemplatesというディレクトリを作ります。

その中にtwig(トゥイッグ)という形式でテンプレートを記述します。jspとか昔のphpみたいなものですが、velocityに似ています。

ファイル名はxxxx.html.twigですが、xxxxのところはrouting.ymlで書いたpathを合わせます。

datemaki.showZairyoList:
  path: '/zairyo-list'

ここではzairyo-listですので、zairyo-list.html.twigというファイル名にします。このファイルの中身は以下のようにHTMLの中にプレースホルダーを記述するものです。

<h4>記事「{{ title }}」です。</h4>

<ol>
  {% for item in items %}
    <li>{{ item.name }}</li>
  {% endfor %}
</ol>

twigはDrupalだけでなく、幅広く使われているPHPのテンプレートエンジンです。検索するとドキュメントを調べることができるでしょう。

コントローラーを修正する

4つ目のステップとして、DatemakiController.phpを修正する必要があります。そのままだとコード内にそのままHTMLを吐き出すようになっているからです。

修正後のDatemakiController.php

<?php

namespace Drupal\datemaki\Controller;

use Drupal\Core\Controller\ControllerBase;
/**
 * This is my datemaki controller.
 */
class DatemakiController {

  public function showZairyoList() {

    $zairyoArray = [
      ['name' => '卵'],
      ['name' => '塩'],
      ['name' => '砂糖'],
      ['name' => 'はんぺん'],
      ['name' => 'サラダ油'],
    ];

    return [
      '#theme' => 'zairyo-list',
      '#items' => $zairyoArray,
      '#title' => '伊達巻',
    ];

  }
}

forループでzairyoArray配列から<li>タグを結合していく部分を取りました。

returnのところを比べてみましょう。
修正前

    return [
      '#type' => 'markup',
      '#markup' => '<ol>' . $output . '</ol>',
    ];

修正後

    return [
      '#theme' => 'zairyo-list',
      '#items' => $zairyoArray,
      '#title' => '伊達巻',
    ];

がらっと変わっています。#typeがなくなり、#themeを返します。themeの値は、twigテンプレートのファイル名の最初の部分です。
zairyo-list.html.twig なので、zairyo-list を指定します。

#itemsは中身となる配列を入れます。$zairyoArrayですね。

#titleはページの<title>タグを上書きします。それだけでなく、zairyo-list.html.twig内の

{{ title }}

としても表示に使えます。前との違いがわかるように

<h4>記事「{{ title }}」です。</h4>

とタイトルを

記事「」です。

と表示するようにしました。

テンプレートでの表示を確認

先ほどと同じように、.routing.ymlでpathに記述したURIにブラウザでアクセスします。キャッシュをクリアする必要があるかもしれません。
http://localhost/zairyo-list

ちゃんとテンプレートから表示されていますね。

CSSの追加

次はそろそろスタイルシートで表示を制御したいところです。そのためにはライブラリという仕組みを使います。

1. xxxxx.libraries.ymlを作成する
2. cssディレクトリを作成する
3. その中にcssファイルを作成する
4. xxx.html.twigファイルを修正する

まずはモジュールのディレクトリ直下に、datemaki.libraries.ymlというファイルを作成します。このように書きます。

datemaki-css:
  css:
    theme:
      css/datemaki.css: {}

次にこれに沿ったディレクトリとファイルを用意します。

モジュールのディレクトリ直下に、cssというディレクトリを作成します。

その中にdatemaki.cssという名前のファイルを作成します。こんなように書いてみました。

h4{
	color: red;
	font-size: 1.4em;
}
li.zairyo{
	padding: 10px 5px;
	font-weight: bold;
	font-color: green;
}

テンプレートの修正

次にテンプレートファイルに2つの修正を加えます。
1. attach_libraryの記載
2. 
class属性の追加

attach_libraryの記載

zairyo-list.html.twigを開き先頭に、

{{ attach_library('datemaki/datemaki-css') }}

と追加します。attach_libraryの中のパスは、「モジュール/<datemaki.libraries.ymlで指定したライブラリ名>」となります。

datemaki-css:
  css:
    theme:
      css/datemaki.css: {}

でしたので、datamaki-css となります。datemaki.libraries.ymlでは、cssの子要素themeの中にcssファイルへのパスが書かれています。

class属性の追加

続いてclass属性を追加したタグを作ります。

<li class='zairyo'>{{ item.name }}</li>

と、<li>タグにclassであるzairyoを追加しただけです。

完成形はこのようになります。

{{ attach_library('datemaki/datemaki-css') }}

<h4>記事「{{ title }}」です。</h4>

<ol>
  {% for item in items %}
    <li class='zairyo'>{{ item.name }}</li>
  {% endfor %}
</ol>

cssの反映を確認する

一度キャッシュをクリアします。先ほどと同じように、.routing.ymlでpathに記述したURIにブラウザでアクセスします。
http://localhost/zairyo-list

ちゃんと反映されているようですね。色も赤になったり、paddingで指定した行間が取れています。念のためブラウザの「要素を検証する」で確認してみましょう(Chromeの場合)。

付いているclass属性に対してcssの指定が効いていますね。これでcssをライブラリとして追加することができました。
 ※ cssのファイル名がこの画面上ではcss_6VGvhJPZSxtnNB7olLA_xbGDIk_TzuhUPFfbBeCp3oA.css?pnnbfv
となっています。これはDrupalがcssをキャッシュしているからです。なので変更した時にはキャッシュをクリアしています。

javascriptも同じ要領でcssのようにライブラリとして追加できます。CDNで指定することもできます。

ドキュメント

https://www.drupal.org/docs/8/creating-custom-modules/adding-stylesheets-css-and-javascript-js-to-a-drupal-8-module

まとめ

Drupal 8で初めて自分でモジュールを作りたい時のための方法をまとめました。Drupal 7に比べていろいろなところに記述が分散するため迷いますが、整理された記述ですので綺麗に書いていくことができます。

サードパーティのモジュールが当てにならないので自分で作ることが多いでしょうが、パワフルなフォーム制御とかあるので積極的に使っていきたいところです。

Drupal 8関連の情報はこちらのサイトにも掲載します。


この記事が気に入ったらサポートをしてみませんか?