Simple strategy pattern with Symfony

Simple strategy pattern with Symfony

The strategy pattern is a very easy implementation with the DIC from Symfony. Here is how:

First let's define an interface for our strategies:

namespace App\Domain\CustomProcess;

interface MyStrategyInterface
{
    public function execute(Whatever $input);
    public function supports(Whatever $input);
}

Then, we will add the tag app.my_strategy in our services.yaml file, so every service which implements the previous interface will automatically receive the tag.

services:
    _instanceof:
        App\Domain\CustomProcess\MyStrategyInterface:
            tags: ['app.my_strategy']

Still in our services.yaml file you can then use the following syntax:

services:
    App\Domain\Doer:
        arguments:
            $strategies: !tagged_iterator app.my_strategy

An example for a Doer class could be the following:

class Doer
{
    private iterable $strategies;
    
    public function __construct(iterable $strategies)
    {
        $this->strategies = $strategies;
    }
    
    public function doSomeWorkOnInput(Whatever $input)
    {
        // In here, you could imagine an algorithm that will try to guess
        // what is the best strategy, but I added a support method
        // on the interface do we will use it.
        foreach ($this->strategies as $strategy) {
            if ($strategy->support($input)) {
                return $strategy->execute($input);
            }
        }
        
        throw new ApplicationLogicException('The given input is not supported.');
    }
}

Hope you'll like it!

Bonus!

If you do not want to manually define your service for the Doer class or if you want to inject the strategy in many places, you can use the section bind of the service.yaml file to enable autowiring for your strategy!

services:
    _defaults:
        bind:
            # I would recommend a better name, but at least you get it
            iterable $strategies: !tagged_iterator app.my_strategy
    

Follow us on Twitter! https://twitter.com/swagdotind