注入提供者服务或容器。好的做法

时间:2016-04-21 09:33:16

标签: php dependency-injection symfony

我的问题更多地是对良好实践方面最佳解决方案的疑问。

想象一下,我们需要根据来自实体的一个参数来实现处理程序。 让我解释一下

OPTION1

  • 服务/提供者/ HSBCProvider
  • 服务/提供者/ BarclaysProvider
  • 服务/ BankHandler
  • 控制器/ BankController

BankHandler

class BankHandler {
  private $container;
  function __contructor($container) {
    $this->container = $container;
  }
  function create($account) {
    $provider = $this->container->get('service.provider.'.$account->getName());
    $provider->do();
  }
}

BankController行动

public function createAction($id) {
   $account = $repository->getAccount($id);
   $bankHandler = $this->get('service.bank_handler');
   $bankHandler->create($account);
}

选项2

  • 服务/提供者/ HSBCProvider
  • 服务/提供者/ BarclaysProvider
  • 控制器/ BankController

BankController行动

public function createAction($id) {
   $account = $repository->getAccount($id);
   $bankProvider = $this->get('service.provider.'.account->getName());
   $bankProvider->do();
}

使用此选项不再需要BankHandler类

我正在简化创建和动作中的所有逻辑。

我不喜欢选项1因为我正在注入容器。 我不喜欢Option 2 cos动作控制器有太多的逻辑(胖控制器?)。

还有其他更好的解决方案吗?

1 个答案:

答案 0 :(得分:0)

为所有提供程序创建一个注册表服务,将其注入处理程序并从中获取提供程序。有些东西......

class BankProviderRegistry
{
    /**
     * @var array|BankProviderInterface[]
     */
    private $providers = array();

    public function __construct(array $providers = array())
    {
        foreach($providers as $name => $provider) {
            $this->addProvider($name, $provider);
        }
    }

    /**
     * Add provider to registry
     *
     * @param string $name
     * @param BankproviderInterface $provider
     */
    public function addProvider($name, BankProviderInterface $provider)
    {
        $this->provider[$name] = $provider;
    }

    /**
     * Get provider by name
     *
     * @param string $name
     * @return BankproviderInterface
     */
    public function getProvider($name)
    {
        if (!isset($this->providers[$name])) {
            throw new \Exception(sprintf('Provider "%s" is not registered', $name));
        }

        return $this->providers[$name]; 
    }
}

您可以在服务中添加这些内容,例如..

app.registry.bank_provider:
    class: AppBundle\Registry\BankProviderRegistry
    arguments:
        - 
            'a name': '@app.provider.a_name' 
            'another name': '@app.provider.another_name' 

..,在您的DI扩展中,在编译器传递中,或者可能在其他地方我没有想过。

然后你将它传递给你的处理程序并获得提供者...

class BankHandler
{
    private $registry;

    public function __contruct(BankProviderRegistry $registry) {
        $this->registry = $registry;
    }

    public function create($account) {
        $provider = $this->registry->getProvider($account->getName());
        $provider->do();
    }
}