簡體   English   中英

Symfony 2:解決循環引用

[英]Symfony 2: Resolve circular reference

我正在研究 Symfony 2 WebApp 項目。 綜合商店的邏輯在MyShopBundle實現。

在向包中添加Twig Extension后,我得到一個異常:

我完全理解這條消息的含義,但到目前為止我沒有找到解決問題的方法:

PaymentServices中的MyShopBundle提供與支付過程相關的所有類型的不同服務。 除其他外,它還會觀察付款狀態並自動向用戶發送電子郵件通知。 另外它提供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 --> Twig --> ShopExtension --> PaymentService

問題是:如何解決這個問題?

我發現了其他問題,在 Symfony 中處理循環引用。 但它們都與使用一些常見 Bundles/Services 的特殊情況有關,例如DoctrineFOSUserBundle等。這些線程中討論的解決方案在這里不起作用。

顯而易見的解決方案是將PaymentService分成兩部分:一部分包含isPaymentComplete(int userId) ,另一部分提供updatePaymentStatus 但這並不像聽起來那么容易,因為這兩種方法使用其他常見的PaymentService方法。 為了避免更深地移動杠桿上的循環引用,我需要將PaymentService分成三個部分:

  • Service1 包括isPaymentComplete
  • Service2 包括updatePaymentStatus
  • Service3 包括 Service1 和 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 }

結果還是一樣。

那么:是否有任何干凈的解決方案來解決這個引用問題?

這個問題意味着你需要有更多的服務和更少的依賴。 例如,您可以擁有像 clientMailProvider 這樣的服務,它會獲取 twig html 電子郵件並將其與您的數據混合。 例如,該服務將由商店支付服務或在其他服務中調用。

現在對於您的問題,我認為您可以注入 twig 的模板部分而不是整個服務:

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));
        ...
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM