2016-05-02 30 views
1

我正在开发一个Symfony 2 WebApp项目。综合商店的逻辑在MyShopBundle执行。Symfony 2:解决循环引用

添加Twig Extension到包后,我得到一个异常:

我完全理解这个信息的意思,但到目前为止,我没有发现任何的解决方案来解决这个问题:

PaymentServicesMyShopBundle报价内与付款过程相关的各种不同的服务。除此之外,它还会观察付款状态并自动向用户发送电子邮件通知。另外它提供了isPaymentComplete(int userId)

要从Twig模板呈现电子邮件的内容,PaymentServices需要参考Twig_Environment。该服务会从它的构造这个参考:

class MyPaymentService { 
    protected $twig; 

    public function __construct(\Twig_Environment $twig, ...) { 
     $this->twig = $twig; 
     ... 
    } 

    public function updatePaymentStatus(int userId) { 
     // Update Payment 
     ... 

     // Send notification to user 
     $mailBody = $this->twig->render('MyShopBundle:Emails:statusUpdate.html.twig', array('user_name' => $username)); 
     ... 
    } 

    public function isPaymentComplete(int userId) { 
     ... 
     return true; 
    } 
} 

在另一方面,枝条扩展需要的PaymentService参考,创建的isPaymentComplete(int userId)树枝版本:

class ShopExtension extends \Twig_Extension { 
    private $paymentService; 

    public function __construct(PaymentService $service, ...) { 
     $this->paymentService = $service; 
     ... 
    } 

    public function getName() { 
     return 'my_shop_bundle_extension'; 
    } 

    public function getFunctions() { 
     $functions = array(); 

     $functions[] = new \Twig_SimpleFunction('msb_IsPaymentComplete', array(
      $this, 
      'msb_IsPaymentComplete' 
     )); 

     return $functions; 
    } 

    public function msb_IsPaymentComplete($user) { 
     if ($this->paymentService) 
      return $this->paymentService->isPaymentComplete($user); 
     else 
      return false; 
    } 
} 

这是服务定义在service.yml

services: 
    shop.payment.service: 
     class: MyShopBundle\Service\PaymentService 
     arguments: 
      - "@twig" 
      - ... 

    app_subscription.twig_extension: 
     class: MyShopBundle\Twig\ShopExtension 
     arguments: 
      - "@shop.payment.service" 
     tags: 
      - { name: twig.extension } 

异常的来源是明确的:

PaymentService - >嫩枝 - > ShopExtension - > PaymentService

的问题是:如何解决这个问题?

我发现了其他问题,在Symfony中处理循环引用。但它们都与一些特殊情况有关,例如使用一些常见的Bundles/Services,如Doctrine,FOSUserBundle等。这些线程中讨论的解决方案在此不起作用。

明显的解决方案是将PaymentService分为两部分:一部分包括isPaymentComplete(int userId),另一部分提供updatePaymentStatus。但是这不像它的声音那样容易,因为这两种方法使用其他常见的方法。为避免刚前进杠杆循环引用更深我需要PaymentService分为三个部分:

  • 服务1包括isPaymentComplete
  • 服务2包括updatePaymentStatus
  • 服务3包括由服务1和2
  • 使用的所有常用的方法

这将工作(很可能),但会非常非常丑陋。这三个服务中的所有方法都具有相同的目的(处理付款),因此应包含在同一服务中。将服务分解成不同的部分与代码结构无关,但只能通过破解循环引用来解决。

我已经尝试从构造函数的引用移动到一个setter:

services: 
    shop.payment.service: 
     class: MyShopBundle\Service\PaymentService 
     calls: 
      - [ setTwig, [ "@twig" ] ] 

    app_subscription.twig_extension: 
     class: MyShopBundle\Twig\ShopExtension 
     calls: 
      - [ setService, [ "@shop.payment.service" ] ] 
     tags: 
      - { name: twig.extension } 

,结果还是一样。

那么:有没有干净解决方案来解决这个参考问题?

+0

你可以拆分付款服务,以便更新支付信息和请求付款的完成状态是分开的。 – xabbuh

回答

1

这个问题意味着您需要拥有更少的依赖性服务。例如,你可以有一个像clientMailProvider这样的服务,它可以获得twig的html电子邮件,并用你的数据来保存它。例如,该服务将由商店付款服务或其他服务调用。

现在对于你的问题,我想你可以注入树枝,而不是整个服务的模板部分:

services: 
    shop.payment.service: 
     class: MyShopBundle\Service\PaymentService 
     arguments: 
      - "@templating" 

服务

use Symfony\Component\Templating\EngineInterface; 

class MyPaymentService { 
    protected $templating; 

    public function __construct(EngineInterface $templating, ...) { 
     $this->templating= $templating; 
     ... 
    } 

    public function updatePaymentStatus(int userId) { 
     // Update Payment 
     ... 

     // Send notification to user 
     $mailBody = $this->templating->render('MyShopBundle:Emails:statusUpdate.html.twig', array('user_name' => $username)); 
     ... 
    }