wire / drupal で遊ぼう

未だ意味不明の wire / drupal で遊んでいきます。
[前回](https://qiita.com/tnakai-r2/items/b794dcff5d5d9bd3999b)はチュートリアルをコピペしてカウンターを作成しました。

今回は記事一覧ページコンポーネントを生成してます。
実装内容はほぼ[公式のトップページ](https://wire-drupal.com/)の内容となっています。



## 準備
コマンドでコンポーネントを作成
```
drush generate wire
```

対話の内容  
![スクリーンショット 2023-07-26 22.51.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1323938/c459b702-3518-56ad-b9c3-1a12fad3ecdd.png)  
エンティティクエリを使用するため、`entity_type.manager`を選択しています。

生成されたファイル

```ArticleList.php
class ArticleList extends WireComponent {

  protected ?EntityTypeManagerInterface $entityTypeManager;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = new static($configuration, $plugin_id, $plugin_definition);
    $instance->entityTypeManager = $container->get('entity_type.manager');
    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  public function render(): ?View {
    return View::fromTpl('article_list');
  }

}
```

## 記事一覧を取得し表示
render() メソッド内でノードを取得してみます。
```php
  public function render(): ?View {
    $node_storage = $this->entityTypeManager->getStorage('node');
    $nids = $node_storage->getQuery()
      ->accessCheck(TRUE)
      ->condition('type', 'article')
      ->condition('status', 1)
      ->execute();
    if (empty($nids)) {
      return NULL;
    }
    $nodes = $node_storage->loadMultiple($nids);

    // 第2に引数にテンプレートに渡す値を設定.
    return View::fromTpl('article_list', [
      'nodes' => $nodes,
    ]);
  }
```
エンティティクエリを使用して事前に作っておいた aritcle コンテンツタイプからすべての記事を取得しました。
エンティティクエリは[こちら](https://qiita.com/863/items/111c0f73be175ed67a74)の記事を参照しました。

テンプレートで表示してみます。
```twig:article_list.html.twig
<div>
  <ul>
    {% for node in nodes %}
      <a href="{{ path('entity.node.canonical', {'node': node.id}) }}">
        <li>{{ node.label }}</li>
      </a>
      タグ: {{ node.field_tags.entity.label }}
    {% endfor %}
  </ul>
</div>
```
パスは[こちら](https://www.drupal.org/docs/develop/theming-drupal/twig-in-drupal/functions-in-twig-templates#s-pathname-parameters-options)のドキュメントを参照しました。
タグはタクソノミーで実装しており、エンティティ参照フィールドなので `node.{エンティティ参照フィールド}.entity.{取得したい値}` といった形で参照します。

結果
![スクリーンショット 2023-07-26 23.13.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1323938/5ea63941-24d0-95f0-969e-fdac5b3568d8.png)

一旦表示はできました。
ただ表示するだけでは Drupal デフォルトの機能を使うほうが良さ気です。

> リアクティブコンポーネントの作成に JS フレームワークは必要ありません

とあるので、リアクティブに動作するか確認するため検索機能を追加してみます。

## 検索機能
フロントから値をPHPに渡す必要があるのでそれようの input タグを用意します。
```twig:article_list.html.tiwg
  <input
    wire:model="search"
    type="search"
    placeholder="Search by title..."
  >
```

次にバックエンドです。
まずプロパティとして `wire:model` でセットした `search` を定義します。
```php
  /**
   * 検索ワード.
   *
   * @var string
   */
  public string $search = '';
```
さらにフロントから受け取った値 $search で絞り込みができるようクエリを書き換えます。

```php
    $nids = $node_storage->getQuery()
      ->accessCheck(TRUE)
      ->condition('type', 'article')
      ->condition('status', 1)
      // 追加分
      ->condition('title', '%' . addcslashes($this->search, '\%_') . '%', 'LIKE')
      ->execute();
```

結果
`p`で検索するとリロードなく特定の記事だけに絞り込めました。
![スクリーンショット 2023-07-29 10.25.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1323938/c8cef5b1-1f12-bb54-6034-57fb61ac8635.png)

ただこの実装だと問題がありました。
NULL を返すとだめっぽいです。
```php
    if (empty($nids)) {
      return NULL;
    }
```
以下のように変更してみました。
```php
    if (empty($nids)) {
      return View::fromTpl('article_list', [
        'message' => '記事が見つかりませんでした。',
      ]);
    }
```

さらに twig も変更し `nodes` がないときは `message` を表示するようにしました。

```twig
  <ul>
    {% if nodes %}
      {% for node in nodes %}
        <a href="{{ path('entity.node.canonical', {'node': node.id}) }}">
          <li>{{ node.label }}</li>
        </a>
        タグ: {{ node.field_tags.entity.label }}
      {% endfor %}
    {% else %}
      {{ message }}
    {% endif %}
  </ul>
```

無事動作しました。

![スクリーンショット 2023-07-29 23.02.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1323938/b5dcc0b9-6249-a35a-dd23-83e92ba4bb51.png)


## まとめ
- JS を書かずに PHP と Twig だけで最近のJSライブラリのような実装ができる。
- REST API とかヘッドレスとかに食って掛かりそうでちょっと楽しみ。