SymfonyとVue.jsを組み合わせるときはSymfony Formを使うのは諦めた方が良さそう

初めまして。イメージ・マジックのスズキです。
いきなりですが、本稿は『SymfonyとVue.jsを組み合わせるときは「Symfony Forms」の機能を使うのは諦めた方がいいかもしれない』ということを伝えたい、ただそれだけの記事です。『エンジニアたる者、どんなときでもまずは結論から話せ』と、物心ついた頃(嘘)から聞かされてきましたしね。
Symfonyで一般的なデータの入力や保存を行う画面をつくるなら、「Symfony Forms」という機能を利用するのが基本のようです。
公式ドキュメントでも、基本的な実装方法として紹介されています。

Symfony Formsを使うことで、コントローラー側でフォームと画面項目の定義をしておいて、画面側(テンプレート側)では自力でタグを書いたりせずに表示することができます。
試しに、テキスト項目が2つあるだけの画面を作る場合、こういう感じになるでしょうか。
// エンティティ
namespace App\Entity;

class Master
{
    private string $name = '';
    private string $description = '';

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;
        return $this;
    }

    public function getDescription(): string
    {
        return $this->description;
    }

    public function setDescription(string $description): self
    {
        $this->description = $description;
        return $this;
    }
}
// フォーム
namespace App\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

class MasterEditType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('name', TextType::class)
            ->add('desctiption', TextType::class)
        ;
    }
}
// コントローラー
namespace App\Controller;

use App\Entity\Master;
use App\Form\Type\MasterEditType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class MasterEditController extends AbstractController
    public function edit(Request $request) : Response
    {
        $master = new Master();
        // ...
        
        $form = $this->createForm(MasterEditType::class, $master);

        return $this->render('master/edit.html.twig', [
            'form' => $form->createView(),
        ]);
    }
}
<!-- 画面テンプレート(Symfony Form使用) -->
<div>
    <div>
        <label>名称</label>
        {{ form_widget(form.name) }}
    </div>
    <div>
        <label>説明</label>
        {{ form_widget(form.description) }}
    </div>
</div>
画面のテンプレートには <input type="text"> といったごく普通のHTMLタグが登場しません。Symfony formsがタグを生成してくれるのですね。

ただ、リッチなフロント画面をVue.jsでごりごり書きたいときは、<input type="text" v-model="master.name">などとVue.jsのディレクティブを入れることになるのですが、Symfony Formsを使っているとそれがしにくくなります。
そんなわけで、Vue.jsでいろいろやりたいならば、Symfonyは使ったとしてもSymfony Formsの機能は使わない方が良さそう、といった印象です。

Symfony Formsを使わずに書くなら、サーバ側ではSymfony Formの代わりに単純なオブジェクトを作ってリターンし、画面側ではVue.jsのお作法でそれを表示するような作りが良さそうです。
先ほどのコードを、Symfony Formsを使わずに(Vue.jsを使えるように)書き直すと、こんな感じでしょうか。
// 変更後のコントローラー(Symfony Formを使わない)
namespace App\Controller;

use App\Entity\Master;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class MasterEditController extends AbstractController
    public function edit(Request $request) : Response
    {
        $master = new Master();
        // ...

        return $this->render('master/edit.html.twig', [
            'master' => [
                'name' => $master->getName(),
                'description' => $master->getDescription(),
            ],
        ]);
    }
}
// 変更後の画面テンプレート(Vue.js使用)
<div>
    <div>
        <label>名称</label>
        <input type="text" v-model="mst.name">
    </div>
    <div>
        <label>説明</label>
        <input type="text" v-model="mst.description">
    </div>
</div>
<!-- Vue.jsのスクリプト部分 -->
<script>
export default {
  props: {
    master: {},
  },
  setup(props) {
    const mst = ref(props.master);
    return {
      mst,
    };
  },
}
</script>
ということで今回は、SymfonyとVue.jsを組み合わせるときのお話でした。Symfony単体やVue.js単体での使い方は情報があっても、組み合わせ方の情報はなかなか無いので書いてみました。
Web界隈はフレームワークやライブラリがたくさんあって、組み合わせるときは試行錯誤が要りますね。