Symfony UXを試してみた

# Symfony UXとは

こちらに詳しく書いてあります。
https://symfony.com/blog/new-in-symfony-the-ux-initiative-a-new-javascript-ecosystem-for-symfony


噛み砕いて説明すると、ユーザーエクスペリエンスを重視した直感的でモダンなWEBサイトの開発にJavaScriptは必要不可欠ですが、モノリシックなWEBアプリを作る時のJavaScriptの開発は結構考えることが多く、手間がかかります。パッケージを選択し、それらを構成し、それらをページに統合し、フロントエンドコードをインフラストラクチャの他の部分と相互作用させる、、などなど。
この問題を解決するために考案されたのがSymfony UXです。Symfony UXはSymfonyとJavaScriptエコシステムの間橋渡しをするためのツールであり、これを用いるとこんな風にJavaScriptのライブラリを使うことができます。

また、Symfony UXは特定のJavaScriptフレームワークに依存していないので、必要に応じて、React、Vue、などのフレームワークを使用できます。

```php:コントローラー
use Symfony\UX\Chartjs\Builder\ChartBuilderInterface;
use Symfony\UX\Chartjs\Model\Chart;

class HomeController extends AbstractController
{
    /**
     * @Route("/", name="homepage")
     */
    public function index(ChartBuilderInterface $chartBuilder): Response
    {
        $chart = $chartBuilder->createChart(Chart::TYPE_LINE);
        $chart->setData([
            'labels' => ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
            'datasets' => [
                [
                    'label' => 'My First dataset',
                    'backgroundColor' => 'rgb(255, 99, 132)',
                    'borderColor' => 'rgb(255, 99, 132)',
                    'data' => [0, 10, 5, 2, 20, 30, 45],
                ],
            ],
        ]);

        $chart->setOptions([/* ... */]);

        return $this->render('home/index.html.twig', [
            'chart' => $chart,
        ]);
    }
}
```

```twig:ビュー
{{ render_chart(chart) }}

{# You can pass HTML attributes as a second argument to add them on the <canvas> tag #}
{{ render_chart(chart, {'class': 'my-chart'}) }}
```

まだ正式にリリースされた訳ではなく開発段階ですが、面白そうなので触ってみました。


# 触ってみる


まずはプロジェクトの作成

```shell
$ symfony new ux-test --full
```

Webpack encore BundleとSymfony UXのチャートライブラリをインストール

```shell
$ composer req symfony/webpack-encore-bundle symfony/ux-chartjs   
```

すると、SymfonyがSymfony UXのライブラリを見つけ、`package.json`に自動で次の記述を追加してくれます。

```json:package.json
{
    "devDependencies": {
        ...
        "@symfony/ux-chartjs": "file:vendor/symfony/ux-chartjs/Resources/assets"
    }
}
```

また、`assets/controllers.json`が自動で作成されます。

```json/controllers.json
{
    "controllers": {
        "@symfony/ux-chartjs": {
            "chart": {
                "enabled": true,
                "fetch": "eager"
            }
        }
    },
    "entrypoints": []
}
```


JavaScriptの依存をインストールし、ビルドします。

```shell
$ yarn install
$ yarn  dev
```

JavaScript関連の作業は以上で終わりです！あとはコントローラーとビューを作るだけです。
以下のコマンドでコントローラーとビューを作成します。

```
$ bin/console make:controller HomeController
```

作成されたコントローラーを次のように修正します。Chart.jsに渡すオプション類を全てPHP上完結させることができています。

```php:src/HomeController.php
...
<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\UX\Chartjs\Builder\ChartBuilderInterface;
use Symfony\UX\Chartjs\Model\Chart;

class HomeController extends AbstractController
{
    /**
     * @Route("/home", name="home")
     */
    public function index(ChartBuilderInterface $chartBuilder): Response
    {
        $chart = $chartBuilder->createChart(Chart::TYPE_LINE);
        $chart->setData([
            'labels' => ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
            'datasets' => [
                [
                    'label' => 'My First dataset',
                    'backgroundColor' => 'rgb(255, 99, 132)',
                    'borderColor' => 'rgb(255, 99, 132)',
                    'data' => [0, 10, 5, 2, 20, 30, 45],
                ],
            ],
        ]);

        $chart->setOptions([/* ... */]);

        return $this->render('home/index.html.twig', [
            'chart' => $chart,
        ]);
    }
}
```

ビューではコントローラーで作成したchartモデルをレンダリング関数に渡すだけです。

```twig:templates/home/index.html.twig
{% extends 'base.html.twig' %}

{% block title %}Hello HomeController!{% endblock %}

{% block body %}
    {{ render_chart(chart) }}
{% endblock %}
```

`templates/base.html.twig`でJavaScriptを読み込むのも忘れずに。!


```twig:templates/base.html.twig
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Welcome!{% endblock %}</title>
        {# Run `composer require symfony/webpack-encore-bundle`
           and uncomment the following Encore helpers to start using Symfony UX #}
        {% block stylesheets %}
            {#{{ encore_entry_link_tags('app') }}#}
        {% endblock %}

        {% block javascripts %}
            {{ encore_entry_script_tags('app') }} # ←　コメントアウトを解除して、ビルドしたJavaScriptを読み込ませる
        {% endblock %}
    </head>
    <body>
        {% block body %}{% endblock %}
    </body>
</html>
```

サーバーを立てて、https://127.0.0.1:8000 へアクセスするとこのような画面が出てくるはずです。完成！

```shell
$ symfony server:start
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614264/460bc79f-4139-fcd7-4115-5c1f1b653c59.png">


# 所感
いままでは、グラフの表示などでJavaScriptのライブラリを使おうとするとテンプレート上で`for`文や`if`文を駆使することが必要で、どうしても可読性が落ちてしまっていました。Symfony UXを使うことで、JavaScriptに渡すパラメータなどを全てPHP上で完結できるようになるのはとても良いなと思いました。

ただ、まだ開発段階のアイデアなので対応しているJavaScriptのパッケージはとても少ないのが難点かなと思いました。また、レンダリング関数の実装によってはJavaScriptライブラリネイティブでは使えるオプションが使えなくなってしまったりということもあるのかなと。
また、API-SPA構成のアプリではまず使われないと思うので、そう行った面でも開発が進むのか心配です。個人的にはモノリシックなアプリは好きなので開発が活発になると嬉しいのですが(´·ω·`)