🎻

[Symfony] 他のエンティティの状態によって値が決まるような属性はエンティティ自体に持たせるよりTwig関数を作るほうがよさそう

2020/06/26に公開

以前、[Symfony] 他のエンティティの状態によって値が決まるような属性はEntityListenerのPostLoadでセットしてあげる という記事を書きましたが、最近はそれよりもこっちのやり方のほうがいいなと思っているので残しておきます。

やりたいこと

要件の具体例は 過去記事 のほうを参照していただきたいのですが、要するに何がしたいかと言うと、

  • エンティティがある
  • そのエンティティは他のエンティティの状態によって決まるような属性を持っている
  • そのような属性はプロパティとして永続化したくはなく、アプリ側で他のエンティティの状態を調べて属性を後付けで決定したい

ということでした。

やり方:Twig関数で都度算出する

これに対して過去記事では「 postLoad のタイミングで状態を算出して、永続化対象でないプロパティにセットする」という方法をとっていましたが、それよりも 「エンティティを渡せば算出結果の状態を返してくれるようなTwig関数を作る」 という方法のほうがシンプルでいいなと最近は思っています。

もともと、関連エンティティの状態から状態を算出する処理自体はリポジトリに実装している想定だったので、PHP側でその状態を知りたい場合は普通にリポジトリをインジェクトすれば事足りていました。

つまり、Twig側でエンティティだけを持っているときに、 task.isComplete のように状態を取得したいという同期でわざわざプロパティにセットしていたのですが、よく考えたら「Twig関数にエンティティを渡せば状態を算出してくれる」という実装にするだけで解決じゃんということにあるとき気がつきました😅

コードの例としては以下のような感じですね。

class AppExtension extends AbstractExtension
{
    private $fooRepository;

    public function __construct(FooRepository $fooRepository)
    {
        $this->fooRepository = $fooRepository;
    }

    public function getFunctions()
    {
        return [
            new TwigFunction('isComplete', [$this, 'isComplete']),
        ];
    }

    public function isComplete(Task $task)
    {
        $isComplete = someCalculation($this->fooRepository->findSomethingByTask($task));
        
        return $isComplete;
    }
}
{# before #}
{{ task.isComplete }}

{# after #}
{{ isComplete(task) }}

まとめ

  • エンティティに「他のエンティティの状態によって決まる」ような属性がある場合は、エンティティ自体に持たせるよりも都度算出するためのTwig関数を作るほうがよさそう(タイトルのまんま)
GitHubで編集を提案

Discussion