JavaScriptを書かずにフロントエンドをリッチにする、"Symfony UX"

[Symfony Component Advent Calendar 2022](https://qiita.com/advent-calendar/2022/symfony-component)の24日目の記事です。

## 最初に
[Symfony](https://symfony.com)はPHPのフレームワークのひとつです。しかし、公式サイトの説明文には

> Symfony is a set of PHP Components, a Web Application framework, a Philosophy, and a Community — all working together in harmony.
  （SymfonyはPHPコンポーネントのセットで、Webアプリケーションフレームワークで、哲学、そしてコミュニティです。それらがハーモニーを奏でながら動作しています。）

と書かれている通り、PHPコンポーネントのセットで、たくさんのコンポーネントを提供しており、それらを組み合わせてひとつのフレームワークとして動作しています。Symfonyのコンポーネントは、Symfony上だけで動作するのではなく、他のPHPフレームワークやアプリケーションでも動作している強力なものが揃っています。

今回はそれらの中から、役立ちそうなもの・お薦めしたいものを紹介していきたいと思います。

※記事内ではautoloadのインポートは省略します。


## JavaScriptを書かずにフロントエンドをリッチにする、"Symfony UX"

[Symfony UX](https://ux.symfony.com/)は、フロントエンド実装を効率的に行う**コンポーネント群**です。


### インストール

今までのコンポーネントとは違い、`Symfony UXをインストール`ということはできず、それぞれのコンポーネントをひとつずつインストールする必要があります。
また、`Symfony UX`コンポーネントはそれぞれ**JavaScriptライブラリが必要です**。残念ながら、composerでは`packages.json`を更新してくれるものの、JavaScriptのライブラリはインストールできないので、`yarn`もしくは`npm`を実行する必要があります。

```shell
# 例： chartjsインストール
composer require symfony/ux-chartjs

yarn install --force
```

### これはなに

Webサイト・システムを開発する際、画面上でのユーザ体験（UX）をよくするためにはJavaScriptが不可欠です。
本来であれば、これらのJavaScriptはゴリゴリと開発していく必要があります。しかし、バックエンドで出力したHTMLにJavaScriptを組み込んでいくのは大変な労力が必要です。また、必要なJavaScriptライブラリの管理もとても困難です。

その労力を少しでも軽くするため、`Symfony UX`が生まれました。`Symfony UX`は、**実現したいこと単位**でコンポーネントが用意されており、それぞれの**必要なJavaScriptライブラリの自動設定**、**UXを実現するためのJavaScriptの自動生成**、**UXに適切に値を渡すためのPHPクラスの提供**を行います。

`Symfony UX`は[Stimulus](https://stimulus.hotwired.dev/)をベースに作成されています。StimulusはHTMLタグに対して機能をバインドする作りとなっており、なんと**React, Vue, Angularなど他のJavaScriptフレームワークと共存が可能**になっています。


### 主な種類

`Symfony UX`は現在13のコンポーネントが用意されています。厳密に種類が分かれているわけではありませんが、おおよそ4種類の機能にわけられます。

| 種類 | 概要 |
|---|---|
| 見た目系 | JavaScriptライブラリを使い、画面の見た目を向上する |
| フォーム系 | JavaScriptライブラリを使い、フォームの利便性を向上する |
| Twig系 | Twigを拡張し、再利用性を向上する |
| 統合系 | 別のJavaScriptフレームワークを統合し、開発効率を向上する |


### 例：グラフ表示

例として、グラフ（正確にはチャート）を表示します。`ux-chartjs`は、[Chat.js](https://www.chartjs.org/)を使ってグラフ表示するコンポーネントです。本来であれば、JavaScriptを書いてグラフを描画しますが、JavaScriptを書かずに描画できるようになります。

個人的にこのコンポーネントが一番`Symfony UX`を説明するのに向いてると思っています。

#### PHP側

`ux-chartjs`には`ChartBuilder`というクラスが用意されています。このビルダーを使って`Chart`オブジェクトを生成し、レスポンスにセットします。

```php:ChartController.php

    public function show(ChartBuilderInterface $chartBuilder): Response
    {
        // グラフオブジェクトを生成する。（線グラフを生成）
        $chart = $chartBuilder->createChart(Chart::TYPE_LINE);

        // データをセットする
        $chart->setData([
            'labels' => ['2022/01', '2022/02', '2022/03'],
            'datasets' => [
                [
                    'label' => '商品1',
                    'data' => [1000, 1500, 1200],
                    'borderColor' => ['rgba(255, 99, 132, 1)'],
                ],
                [
                    'label' => '商品2',
                    'data' => [2000, 1000, 1300],
                    'borderColor' => ['rgba(54, 162, 235, 1)'],
                ],
                [
                    'label' => '商品3',
                    'data' => [500, 1000, 1500],
                    'borderColor' => ['rgba(255, 206, 86, 1)'],
                ],
            ],
        ]);
        
        // オブジェクトをレスポンスにセットする
        return $this->render('index.html.twig', [
            'chart' => $chart,
        ]);
    }
```

#### Twig側

Twig側は、まずヘッダー部にSymfony UXが使えるようにする必要があります。

```twig:base.html.twig
<head>
    {% block stylesheets %}
        {{ encore_entry_link_tags('app') }}
    {% endblock %}
    {% block javascripts %}
        {{ encore_entry_script_tags('app') }}
    {% endblock %}
</head>
```
`{{ encore_entry_script_tags('app') }}`を`javascripts`ブロックに入れることで、`Symfony UX`用のJavaScript、正確には`assets`ディレクトリにあるJavaScriptを読み込んでくれます。

```twig:index.html.twig
<div>
<h2>ここにグラフを表示します。</h2>
{{ render_chart(chart) }}
</div>
```

続いてグラフ表示ですが、`{{ render_chart(chart) }}`を呼び出すだけでOKです。引数で渡している`chart`は先ほどPHP側のレスポンスで用意したものです。
この記述だけで、何十行にもなるJavaScriptを出力してくれます。JavaScriptは一切書いてないですが、JavaScriptが書けました。

## まとめ

今回は`Symfony UX`を紹介しました。個人的にはかなり注目のコンポーネントで、Symfonyのプロジェクトのみでリッチなコンテンツが作れるので、
分けるほどでもないのにフロントエンドとバックエンドが妙に分離してしまうようなプロジェクトを作らなくてもよくなりそうです。
（Symfony UXが抜群に火を吹くのは管理画面系の機能だと思います。）