[英]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 的特殊情況有關,例如Doctrine
、 FOSUserBundle
等。這些線程中討論的解決方案在這里不起作用。
顯而易見的解決方案是將PaymentService
分成兩部分:一部分包含isPaymentComplete(int userId)
,另一部分提供updatePaymentStatus
。 但這並不像聽起來那么容易,因為這兩種方法使用其他常見的PaymentService
方法。 為了避免更深地移動杠桿上的循環引用,我需要將PaymentService
分成三個部分:
isPaymentComplete
updatePaymentStatus
這會起作用(最有可能),但會非常非常丑陋。 這三個服務中的所有方法都用於相同的目的(處理付款),因此應包含在相同的服務中。 將服務分解成不同的部分與代碼結構無關,而只是通過黑客來分解循環引用。
我已經嘗試將引用從構造函數移動到 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.