🍰

[Symfony]デコレータークラスを作って、Entityからビジネスロジックを剥がす

2021/03/30に公開

SymfonyのEntityに、ビジネスロジックを書くことがあると思います。

src/Entity/Item.php
<?php

namespace App\Entity;

class Item {
    private int $id;
    private string $title;
    private bool $isPublished;
    private \DateTime $publishedAt;
    
    // もろもろ割愛
    
    /**
     * 公開する
    */
    public function publish()
    {
        $this->isPublished = true;
        $this->publishedAt = new \DateTime();    
    }
}

この例では、商品を公開する際に、ItemエンティティのisPublishedとpublishedAtを変更するビジネスロジックを持っています。
このビジネスロジックをデコレータークラスを使って、Itemエンティティから剥がします。

実装

src/Core/ItemDecorator.php
<?php

namespace App\Core;

use App\Entity\Item;

class ItemDecorator {
    private Item $item;
    
    public function __construct(Item $item)
    {
        $this->item = $item;
    }
    
    /**
     * 公開する
    */
    public function publish()
    {
        $this->item->setIsPublished(true);
        $this->item->setPublishedAt(new \DateTime());    
    }    
}
src/Entity/Item.php
    
    // もろもろ割愛
    
-    /**
-     * 公開する
-    */
-    public function publish()
-    {
-        $this->isPublished = true;
-        $this->publishedAt = new \DateTime();    
-    }
}

利用例

src/Controller/ItemController.php
<?php

namespace App\Controller;

class ItemController extends AbstractController {
    // もろもろ割愛
    
    #[Route('/item/{id}/publish', name: 'item_publish')]
    public function publish(EntityManagerInterface $em, Item $item)
    {
        $itemDecorator = new ItemDecorator($item);
        $itemDecorator->publish();
        $em->flush();
        
        return $this->redirect('/');
    }
}

デコレータークラスであるItemDecoratorはItemエンティティを持ったクラスです。インスタンス作成時にItemを引数に渡します。
ItemDecorator::publish()でItemエンティティの値を意図したものに変更します。
これで、Itemからビジネスロジックがなくなりました。

Discussion