2011-11-05 40 views
18

我在我的應用程序 - 一個有點複雜的定價機制,這裏有一些我的業務規則設定階段(實體被加粗):Symfony2/Doctrine,必須在我的控制器中放入業務邏輯?和複製控制器?

  • 一個產品可能有獨特的價位爲給定客戶,網站客戶組
  • 一個產品有時可以有一個或多個附加選項可能有自己的價位價格規則
  • A 產品有一個唯一加法由用戶選擇,這實質上是一個價格和一個整數。

現在,我有價位的EntityRepository基本上確定基本產品正確的價格點。 唯一加法選項也是如此。

PricePointRepository

public function getThePrice($Product, $qty, $Website, $Customer = null) 
{ 
    //all logic to get product price for this given instance goes here. Good. 
} 

控制器(簡體)

public function indexAction() 
{ 
    $Product = $em->dostuffwithpostdata; 
    $qty = POST['qty']; //inb4insecure trolls 
    $Website = $em->dostuff(); 
    $Customer = (if user is logged in, return their object with $em, otherwise null as it is a guest or public person); // No business logic here, just understanding the request. 

    $price = $em->getRepository(PricePointRepository)->getThePrice($Product,$qty,Website,$Customer); 

    $Options[] = $em->dostuffwithPOSTdata; 
    $optionsPrice = 0; 
    //Below is some logic directly related to pricing the product. 
    foreach($Options as $option) { 
     if($option->hasRule()) { 
      $optionsPrice += $ruleprice; //after some other stuff of course) 
     } else { 
      $optionsPrice += $em->getRepository(OptionPricePoints)->getPrice($option->getID(),$qty); 
     } 
    } 

    $uniqueAdditionPrice = $em->stuff; 

    $finalprice = $price + $optionsPrice + $uniqueAdditionPrice; //This is logic related to how I price this type of product! 
    $unitprice = $finalprice/$qty; 

    //twig stuff to render and show $finalprice, $unitprice, $uniqueAdditionPrice 
} 

這只是該產品的頁面。當這個邏輯需要重新使用時,當我到購物車,保存訂單等等會發生什麼。如您所見,我始終使用Doctrine根據存儲庫類中的業務邏輯提取數據。

我很高興地歡迎urdoingitwrong的答案,因爲我真的認爲這是錯誤的。我該如何解決這個問題?美好的東西是基本上是這樣一種服務:

$pricer = getPricerService->Pricer($Entities,$postdata,$etc); 
$unitPrice = $pricer->getUnitPrice(); 
$totalPrice = $pricer->getTotalPrice(); 
$optionsPrice = $pricer->getOptionsPrice(); 

但我不知道如何去這樣做的Symfony /教義裏面,特別是教義和庫在控制器進行訪問的方式。

回答

29

你是對的,你應該把所有可重用的業務邏輯放在一個服務上,以便不同的控制器可以重新使用代碼。

你檢查出「如何創建一個服務」文檔:

Service Container Documentation

我雖然給你的速度破敗。

在配置中。陽明您需要定義您的服務:

services: 
    pricing_service: 
     class: Acme\ProductBundle\Service\PricingService 
     arguments: [@doctrine] 

然後你只需要做出一個沼澤標準的PHP類來表示您的服務:

namespace Acme\ProductBundle\Service; 

class PricingService { 

    private $doctrine;   

    function __construct($doctrine) { 
     $this->doctrine = $doctrine; // Note that this was injected using the arguments in the config.yml 
    } 

    // Now the rest of your functions go here such as "getUnitPrice" etc etc. 
} 

最後從一個控制器讓你的服務,你只需要這樣做:

$pricingService = $this->get('pricing_service');

還有其他的方法可以modularise服務等所有服務不卸入config.yml但所有這一切在文檔中有解釋。另外請注意,您可以將任何其他服務注入您的服務中,因此如果您需要諸如arguments: [@doctrine, @security.context, @validator]之類的東西,則可以執行所有這些操作,甚至可以:[@my_other_service]

我懷疑從你的另一個問題注入EntityManager,你可能已經閃閃發光這是儘管!

希望這對你仍然有用!

+0

太棒了 - 謝謝!在你的迴應和庫巴之間,我已經掌握瞭如何完成這部分應用。 – Nick

+0

如果您想在同一事務下合併兩個服務調用,該怎麼辦? – GorillaApe

10

你簡化了你的例子,所以我不知道所有的細節,但這是我的企圖解決你的問題。

請注意,你可能實際上需要更多的一個服務,但你應該得到我的例子的想法。

基本上遵循原則 - 一類有一個責任。

價格計算器計算價格:

namespace MyNamespace; 

interface PriceInterface 
{ 
    public function getUnitPrice(); 

    public function getTotalPrice(); 

    public function getOptionsPrice(); 
} 

價格計算器服務對實體管理器的依賴性:

my_namespace.price_calculator: 
    class:  MyNamespace\PriceCalculator 
    arguments: [ @doctrine.orm.default_entity_manager ] 

控制器

namespace MyNamespace; 

class PriceCalculator 
{ 
    private $entityManager = null; 

    public function __construct(Doctrine\ORM\EntityManager $entityManager) 
    { 
     $this->entityManager = $entityManager; 
    } 

    /** 
    * @return PriceInterface 
    */ 
    public function calculate() 
    { 
     // do your stuff and return Price 
    } 
} 

價格由PriceInterface描述使用價格計算器服務獲得價格:

public function indexAction() 
{ 
    $priceCalculator = $this->get('my_namespace.price_calculator'); 
    $price = $priceCalculator->calculate(); 

    $unitPrice = $price->getUnitPrice(); 
    $totalPrice = $price->getTotalPrice(); 
    $optionsPrice = $price->getOptionsPrice(); 
} 

如果你需要一個請求或其他服務,您可以使用它們DIC或手動作爲參數傳遞給計算()方法注入。

注意,我注入的EntityManagerPriceCalculator服務,但您可以定義數據提供商的服務,並注入他們,而不是(真的爲複雜的東西)。

您也可以將所有查詢都推送到存儲庫並將實體傳遞到您的PriceCalculator的

+0

這與Kasheen的迴應相結合,非常有幫助。謝謝! – Nick