jeudi 28 novembre 2019

Write a class in PHP Symfony 4.4 using the design pattern Factory Method to instantiate Service classes

Using Symfony 4.4 with autowiring activated, I want to instantiate a class using the design-pattern FactoryMethod.

The class instantiated is a service with autowired arguments passed into the constructor.

It work well if the constructor is the same for each type of class to instantiate inside the factory method.

But, each service to instantiate has to autowire some specific service in order to work.

I found that we could use the "setter dependency injection". Articles describing it:

I tried to implement the setter dependency injection but the code inside is never executed.

Considering the articles, we should enter the setters with the PHPDoc "@required" immediately after the __construct method has been called (from what I understood).

It doesn't work with my code (see below).

Is my implementation correct?

Is there a better way of doing it?

My code looks like:

// Controller
/**
 *@Route("/my_action/{param}")
 */
public function my_action (ThingManagerFactory $thingManagerFactory, $param)
{
    $thingManager = $thingManagerFactory->get($param);
    $thingManager->doSomething();
}


// ThingManagerFactory

class ThingManagerFactory
{
    private $firstManager;
    private $secondManager;
    private $thirdManager;

    public function __construct(FirstManager $firstManager, SecondManager $secondManager, ThirdManager $thirdManager)
    {
        $this->firstManager = $firstManager;
        $this->secondManager = $secondManager;
        $this->thirdManager = $thirdManager;
    }

    public function get($param): ThingManagerInterface
    {
        if($param == 1) {
            return new Thing1Manager(
                $this->firstManager,
                $this->secondManager,
                $this->thirdManager,
            );
        } elseif($param == 2) {
            return new Thing2Manager(
                $this->firstManager,
                $this->secondManager,
                $this->thirdManager,
            );
        }

        throw new \InvalidArgumentException("...");
    }
}


// ThingManagerInterface
interface ThingManagerInterface
{
    public function __construct(
            $this->firstManager,
            $this->secondManager,
            $this->thirdManager,
        );
    public function doSomething();
}


// Thing1Manager
class Thing1Manager implements ThingManagerInterface
{
    (...)
    private $spec1Manager;

    public function __construct(
            $this->firstManager,
            $this->secondManager,
            $this->thirdManager,
        )
    {
        (...)
    }

    /**
     * @required
     */
    public function setSpecificManager(Spec1Manager $spec1Manager)
    {
        // this code is never called
        $this->spec1Manager = $spec1Manager;
    }

    public function doSomething()
    {
        // we pass here before going into setSpecificManager
        (...)
    }
}


// Thing2Manager class
// is similar to Thing1Manager with multiple other specific managers.



Thank you for your help.

Aucun commentaire:

Enregistrer un commentaire