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関連の情報はこちらのサイトにも掲載します。