未だ意味不明の wire / drupal で遊んでいきます。
前回はチュートリアルをコピペしてカウンターを作成しました。
今回は記事一覧ページコンポーネントを生成してます。
実装内容はほぼ公式のトップページの内容となっています。
準備
コマンドでコンポーネントを作成
drush generate wire
対話の内容
エンティティクエリを使用するため、entity_type.manager
を選択しています。
生成されたファイル
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() メソッド内でノードを取得してみます。
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 コンテンツタイプからすべての記事を取得しました。
エンティティクエリはこちらの記事を参照しました。
テンプレートで表示してみます。
<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>
パスはこちらのドキュメントを参照しました。
タグはタクソノミーで実装しており、エンティティ参照フィールドなので node.{エンティティ参照フィールド}.entity.{取得したい値}
といった形で参照します。
一旦表示はできました。
ただ表示するだけでは Drupal デフォルトの機能を使うほうが良さ気です。
リアクティブコンポーネントの作成に JS フレームワークは必要ありません
とあるので、リアクティブに動作するか確認するため検索機能を追加してみます。
検索機能
フロントから値をPHPに渡す必要があるのでそれようの input タグを用意します。
<input
wire:model="search"
type="search"
placeholder="Search by title..."
>
次にバックエンドです。
まずプロパティとして wire:model
でセットした search
を定義します。
/**
* 検索ワード.
*
* @var string
*/
public string $search = '';
さらにフロントから受け取った値 $search で絞り込みができるようクエリを書き換えます。
$nids = $node_storage->getQuery()
->accessCheck(TRUE)
->condition('type', 'article')
->condition('status', 1)
// 追加分
->condition('title', '%' . addcslashes($this->search, '\%_') . '%', 'LIKE')
->execute();
結果
p
で検索するとリロードなく特定の記事だけに絞り込めました。
ただこの実装だと問題がありました。
NULL を返すとだめっぽいです。
if (empty($nids)) {
return NULL;
}
以下のように変更してみました。
if (empty($nids)) {
return View::fromTpl('article_list', [
'message' => '記事が見つかりませんでした。',
]);
}
さらに twig も変更し nodes
がないときは message
を表示するようにしました。
<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>
無事動作しました。
まとめ
- JS を書かずに PHP と Twig だけで最近のJSライブラリのような実装ができる。
- REST API とかヘッドレスとかに食って掛かりそうでちょっと楽しみ。