DEV Community

Marat Latypov
Marat Latypov

Posted on

Tagged services in Symfony new look

A few years ago, I wrote an article titled Strategy pattern in Symfony. It was good for its time and is still relevant, but now it's a bit old-fashioned.

Using attributes

Now I'd rather define services using attributes instead of services.yml:

#[AutoconfigureTag(self::TAG)]
interface ImageResizeStrategyInterface
{
    public const TAG = 'image_resize_strategy';
    public function supports(string $imageType): bool;
    public function resize(string $filename, int $newWidth, int $newHeight);
}
Enter fullscreen mode Exit fullscreen mode

Using support method

Another change, I prefer supports method to check if the strategy is applicable to the case.
Every time, every case. This way I don't have to spend any time thinking of naming :)

class ImageJpgResizeStrategy implements ImageResizeStrategyInterface
{
    #[\Override]
    public function supports(string $imageType)
    {
         return 'JPG' === $imageType;
    }
    #[\Override]
    public function resize(string $filename, int $newWidth, int $newHeight)
    {
      ...
    }
}
Enter fullscreen mode Exit fullscreen mode

Using support method our resizer looks quite different now

class ImageResizer
{
    public function __construct(
        /** @var ImageResizeStrategyInterface[] */
        #[TaggedIterator(ImageResizeStrategyInterface::TAG)]
        private readonly iterable $strategies,
    ) {
    }

    public function resize(string $filename, string $extension, int $newWidth, int $newHeight) 
    {
        foreach($this->strategies as $strategy) {
            if($strategy->supports($extension)) {
                $strategy->resize($filename, $newWidth, $newHeight);
                return;
            }
        }

        throw new \Exception('Unhandled extension');
    }
Enter fullscreen mode Exit fullscreen mode

That's it

Top comments (1)

Collapse
 
slowwie profile image
Michael

Thank you for sharing this. I like that you use the tag as a Constant. So you can use it later in the TaggedIterator Attribute.