Symfony Tagged Service vs Factory

时间:2015-11-26 20:27:12

标签: php symfony symfony-2.3

我是Symfony2的新手,有点困惑。对不起,如果这个问题听起来很傻。

creating service with factory Tagged Services 都用于假设创建工厂。

根据上述链接中的文档,我能想出的差异是:

  

对于标记服务:

     
    

您需要编写编译器传递,然后为每个服务定义一个标记。

         

然后写一个工厂(任何类。这应该被称为工厂吗?),它将从编译器传递中获取所有标记服务的对象。另外在这里创建一个getter方法,它将根据一些标准返回对象。

  
     

如果使用工厂创建服务,您只能创建一个服务,并通过调用静态方法将其对象返回给您。

所以,我想,在标记服务中,您可以从众多服务中进行选择,并且在创建逐个服务的情况下,您只能创建单个服务。我认为标记服务已经服务于工厂的目的。为什么我们只能在创建单个对象时才需要工厂服务?可能我在这里有一个误解,但标记服务更好,因为编译器传递是在缓存预热上运行的,标记服务本身存储在那里,所以它会更快。但是,服务也被缓存,因此应该没有太大的区别。但我不确定这种概念化是否正确。

请让我理解两者的概念,让我感到开悟。

1 个答案:

答案 0 :(得分:9)

工厂服务和标记服务具有完全不同的角色。我将尝试通过示例向您说明一些常见情况,当您可能想要使用其中一种情况时。

当服务容器中没有构建服务所需的某些参数时,或者在实例化服务之前需要进行一些准备工作时,通常会使用它。 Symfony会自动检查您的服务是否拥有自己的工厂,或者直接从容器参数构建。

真实世界用例

您有一项处理PayPal付款的服务。要构建它,您需要在PayPal凭据和API端点URL中传递它。

class PayPalPaymentService
{
    // ...

    public function __construct(PayPalCredentials $credentials, $apiEndpoint)
    {
        // ...
    }

    // ...
}

这适合您,但您意识到您需要有两种环境:直播沙盒。您的凭据和API端点URL都会有所不同,具体取决于您所处的环境。

Symfony有几种方法可以为您处理,但其中一种方法是通过工厂服务:您创建一个工厂,根据您当前的情况实例化 PayPalPaymentService 当地环境。

class PayPalPaymentServiceFactory
{
    const SANDBOX_ENDPOINT = '...';
    const LIVE_ENDPOINT = '...';

    private $livePublic;
    // ...

    public function __construct($livePublic, $liveSecret, $sandboxPublic, $sandboxSecret, $kernelEnvironment)
    {
        $this->livePublic = $livePublic;
        // ...
    }

    public function create()
    {
        if ('prod' === $kernelEnvironment) {
            $credentials = new PayPalCredentials($this->livePublic, $this->liveSecret);
        } else {
            $credentials = new PayPalCredentials($this->sandboxPublic, $this->sandboxSecret);
        }
        $url = 'prod' === $kernelEnvironment ? self::LIVE_ENDPOINT : self::SANDBOX_ENDPOINT;

        return new PayPalPaymentService($credentials, $url);
    }
}

现在,每当您注入PayPalPaymentService时,容器将首先要求您的PayPalPaymentServiceFactory创建它,然后注入它。

标记服务

这些完全是另一回事。在整个Symfony代码库中使用标记服务:用于FormTypes,Twig Extensions,Validator等。标记服务的概念是一种非常强大的扩展机制。它允许您将标记您的服务视为用于特定目的的内容。正如我所说,在Symfony代码库中已经有它们的例子,但是这里有一个非常简单的例子来看看你能用它们做些什么:

您的电子商店有付款,并且您有支持的付款处理器列表。每个支付处理器都有自己的结账页面。因此,您决定将其模块化,让其他人为其创建新的支付处理器。

在您的购物车页面上,您需要显示指向所有可用付款处理器结帐页面的链接,为此,您有一项服务可以为您提供所有可用的结帐链接:

class CheckoutLinksProvider
{
    /**
     * @var ProcessorAdapter[]
     */
    private $adapters;

    public function registerProcessor(ProcessorAdapter $adapter)
    {
        $this->adapters = $adapter;
    }

    public function getCheckoutLinks()
    {
        $links = [];
        foreach ($this->adapters as $adapter) {
            $links[] = $adapter->getCheckoutLink();
        }
        return $links;
    }
}

interface ProcessorAdapter
{
    /**
     * @return string Checkout URL link
     */
    public function getCheckoutLink();

    // ...
}

现在,任何人都可以实现ProcessorAdapter并在Github上将其作为捆绑包共享!他们所要做的只是使用您决定的某个标记标记其ProcessorAdapter实施,例如:' my_eshop_processor_adapter'。

在您的核心电子商店系统编译器通过中,您现在可以选择所有ProcessorAdapter实施并在CheckoutLinksProvider服务中注册它们。瞧!您已经拥有完全模块化的支付系统!任何人都可以创建对自定义处理器的支持,您只需下载它们的包并在内核中注册它们,就会出现结帐链接!