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.