Drupal 8.7.x に入る JavaScript 向け Message API を試す

Drupal では、コンテンツ作成時やキャッシュクリア時など様々なサーバで行った処理結果がメッセージとして表示されます。サーバサイドの場合は、`\Drupal\Core\Messenger\MessengerInterface` で定義されている `addMessage()`[^1] などのメソッドを使えば画面に出すメッセージを作成することができます。
一方、クライアントサイドの場合に同様なことをやろうとした時（例えば、Druapl を動かしているサーバ上で REST API を JavaScript から呼び出してコンテンツを作成した時）にも同様にメッセージを出そうとすると、今までは上記の `addMessage()` で出力された HTML をそのまま出力するような処理を書く必要がありました。
以前からこの状況の改善要望を求める issue 作成され、最近 Message API を提供する Drupal 8.7.x 向けのパッチが作成されました。この記事ではそのパッチを当てて Message API を実行するまでを記述します。

## issue とパッチの当て方

### 該当の issue

この issue の場所は [Provide a common API for displaying JavaScript messages](https://www.drupal.org/project/drupal/issues/77245) になります。この中の、~~`	77245-411.patch`~~ `77245-419.patch` が目的のパッチファイルになります。（記事作成時から更新されました。内容は一部コメントと空白の変更なので実装には影響がありません）

【追記2018/12/08】
**この issue が2006年8月に建ち12年の時を経てパッチが、
:clap: :clap: :clap: [ :congratulations: マージされました](https://cgit.drupalcode.org/drupal/commit/?id=280995f) :clap: :clap: :clap:**

### パッチの当て方

パッチを当てるには、Drupal 8.7.x の開発版のソースコードが必要になります。Drupal 8.7.x のアーカイブのダウンロードは[ここ](https://www.drupal.org/project/drupal/releases/8.7.x-dev)でできます。（もちろん、Git コマンドを使って `git clone https://github.com/drupal/drupal.git` でも構いません）
ダウンロードをしたら、パッチを当てます。パッチは [Applying patches](https://www.drupal.org/patch/apply) のやり方に沿ってパッチを当てます。（アーカイブから展開をした場合は patch コマンド、Git コマンドでクローンした場合は git コマンドでパッチを当てます）

## API の実行

API を実行できるようにするためには、`/core/core.libraries.yml` にあるライブラリの `drupal.message` がページ内で呼び出されている必要があります。~~ページを用意するのが面倒なので、~~パッチに付属しているテスト用ページの `/js_message_test_link` にアクセスして試します。

### テストモジュールの有効化

テスト用ページはパッチを当てるとできる新しいモジュールに定義されていますが、テスト用に作成されたモジュールであるためそのままだと `admin/modules` の拡張一覧には出てきません。テスト用のモジュールを拡張一覧に出すためには、`settings.php` に以下の記述を追加する必要があります。

```php:settings.php
// 下記の行を追加
$settings['extension_discovery_scan_tests'] = TRUE;
```

テストモジュールが拡張一覧に出てきたら、`JS Message test module` を有効にします。

### API を試す

`/js_message_test_link` にアクセスすると下記のようなテスト用のボタンがたくさん並んだページが表示されます。（表示は Umami テーマ）このボタンをクリックすると、Drupal のサーバサイドでメッセージを表示させるときと同じようにメッセージが表示されます。
上段の details タグ内に表示されているボタンをクリックすると、テーマの `Status messages` 領域にテストメッセージが表示されます。下段の details タグ内に表示されているボタンをクリックすると、details タグの内部にテストメッセージが表示されます。

![Screen Shot 2018-12-01 at 20.13.43.png](https://qiita-image-store.s3.amazonaws.com/0/51890/2c233964-5ea6-6c0f-0014-88459cc708f8.png)

JavaScript で Message API を呼び出すときは `/core/core.libraries.yml` の `drupal.message` で定義されているライブラリを読み込んだうえで下記のような形で実装します。

```js:message_api_example.js
/*
  Message API はインスタンスを作成するように実装されているので new で呼び出す
  インスタンス作成時に HTML 要素を指定するとその中にメッセージが作成される
*/
const message = new Drupal.Message();

/*
  メッセージは文字列だけを引数に入れると、標準のメッセージを出力する
  メッセージ追加時に ID が返ってくる。この ID は message.select(id) や message.remove(id) で特定のメッセージを選択するときに使用する
*/
const messageId = message.add('hogehoge');

// 警告やエラーの場合は下記のように、type を指定する必要がある
message.add(
  'foobar',
  {
    'type': 'warning',
  }
);
message.add(
  'xyzzy',
  {
    'type': 'error',
  }
);

// message.select(id) は指定された ID の要素を取得する
console.log(message.select(messageId), 'メッセージの要素');

// message.remove(id) は指定された ID の要素を削除する
message.remove(id);

// message.clear() はメッセージを作成する領域内にあるすべてのメッセージを削除する
message.clear();
```

## まとめ

この記事では、Drupal 8.7.x に提供される JavaScript 向けの Message API を試用できるようにする手順を記述しました。
Message API を試用してみた実感としては、メソッドを呼ぶだけで Drupal 標準のメッセージ表示になるため、従来のように表示用の HTML 部分を書く必要がなくなり、その部分に関してはコードの見通しが少し良くなるだろうなと思います。ただ、Message API はインスタンスがないとメッセージ削除などが正しく動かないのでインスタンスの変数の管理が面倒なことになる気がします。

[^1]: [drupal_set_message()](https://api.drupal.org/api/drupal/core%21includes%21bootstrap.inc/function/drupal_set_message/8.5.x) は Drupal 8.5.0 から deprecated になりました。