Search code examples
phpsymfonydependency-injectionfactoryfactory-pattern

Symfony factories: injecting dependencies, autowiring and binding parameters


The Symfony docs don't give a full example of the usage of factories in Symfony.

In my case I have many different services that generate, let's say, different fruits APIs:

  • BananaApiService
  • AppleApiService
  • PearApiService
  • ..

Each service has it's own dependency, the dependency is some bind parameter:

services:
    _defaults:
        autowire: true
        bind:
            $guzzleClientBanana: '@eight_points_guzzle.client.banana'
            $guzzleClientApple: '@eight_points_guzzle.client.apple'
            ...

Services are of example:

# BananaApiService.php

class BananaApiService extends DefaultEndpointService
{
    protected $guzzleClientBanana;

    public function __construct(GuzzleClient $guzzleClientBanana)
    {
        $this->guzzleClientBanana = $guzzleClientBanana;
    }

    public function handleRequest(ApiRequest $apiRequest)
    {
    ...
    }
}

Currently I am not using the factory pattern but instead passing all the services to a manager's constructor which is too dirty and against best practices:

# ApisManagerService

class ApisManagerService
{
    protected $BananaApiService;
    protected $AppleApiService;
    protected $PearApiService;

    public function __construct(BananaApiService $BananaApiService, 
                                AppleApiService $AppleApiService, 
                                PearApiService $PearApiService)
    {
        $this->BananaApiService = $BananaApiService;
        //...
    }

    public function requestDispatcher(ShoppingList $shoppingList): void
    {
        foreach ($shoppingList->getItems() as $item) {
            switch ($item->getName()) {
                case 'banana':
                    $this->BananaApiService->handleRequest($item);
                    break;
                case 'apple':
                    $this->AppleApiService->handleRequest($item);
                    break;
                //...
            }
        }
    }
}

This requestDispatcher is called via some event subscriber:

class EasyAdminSubscriber implements EventSubscriberInterface
{

    public function triggerApisManagerService(GenericEvent $event): void
    {
        /* @var $entity shoppingList */
        $entity = $event->getSubject();

        if (! $entity instanceof shoppingList) {
            return;
        }

        $this->apisManagerService->requestDispatcher($entity);
    }
}

How can I make the code better using Symfony factories (or other Symfony approaches)?


Solution

  • I would advise to take a look at the implementation of strategy pattern for this specific case. It would be a way cleaner solution than all-services constructor injection, especially if there are cases when all services are not needed to be used - with strategy pattern you will use only the needed services (at application run-time), & handle their specific logic.