Symfony2/Doctrine,必须将业务逻辑放在我的控制器中?和复制控制器?

Nic*_*ick 20 model-view-controller orm business-logic symfony doctrine-orm

我的应用程序中有一个复杂的定价机制 - 以下是我设置阶段的一些业务规则(实体是粗体):

  • 一个产品可能具有独特的价位对于给定的客户,网站客户群.
  • 一个产品有时可以有一个或多个附加选项,可能有自己的价格点 价格规则.
  • 产品具有一个独特的添加由用户,这本质上是一种价格和一个整数选择.

现在,我有一个价格点的EntityRepository,基本上确定了基本产品的正确价格点.这同样适用于在独特的加法选项.

PricePointRepository

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

控制器(简化)

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
}
Run Code Online (Sandbox Code Playgroud)

这仅适用于产品页面.当我需要重新使用此逻辑时,当我进入购物车,保存订单等时会发生什么.如您所见,我始终使用Doctrine来根据存储库类中的业务逻辑来提取数据.

我很高兴地欢迎urwingit错误的答案,因为我真的认为这是错的.我该如何解决这个问题?美丽的东西将是一个服务,基本上是这样的:

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

但我不知道如何在Symfony/Doctrine中进行,特别是在控制器中访问Doctrine和Repositories的方式.

Kas*_*een 29

你应该将所有可重复使用的业务逻辑都归结为服务,以便不同的控制器可以重用代码,这是正确的.

您是否查看了"如何创建服务"文档:

服务容器文档

我会尽快给你速度.

在config.yml中,您需要定义您的服务:

services:
    pricing_service:
        class: Acme\ProductBundle\Service\PricingService
        arguments: [@doctrine]
Run Code Online (Sandbox Code Playgroud)

然后你只需要制作一个标准的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.
}
Run Code Online (Sandbox Code Playgroud)

最后,您需要从控制器获取服务:

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

还有其他方法可以模块化服务,例如不将所有服务转储到config.yml中,但所有这些都在文档中进行了解释.另请注意,您可以将任何其他服务注入您的服务中,这样如果您需要的东西,arguments: [@doctrine, @security.context, @validator]您可以做所有这些甚至:[@my_other_service].

我怀疑从你关于注入EntityManager的其他问题,你可能已经知道这是可行的方法!

希望这对你有用!


Jak*_*las 10

你简化了你的例子,所以我真的不知道所有细节,但这里是我的解决问题的方法.

请注意,您实际上可能需要多个服务,但您应该根据我的示例获得想法.

基本上遵循原则 - 一个班级有一个应对能力.

价格计算器计算价格:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

价格由PriceInterface描述:

namespace MyNamespace;

interface PriceInterface
{
    public function getUnitPrice();

    public function getTotalPrice();

    public function getOptionsPrice();
}
Run Code Online (Sandbox Code Playgroud)

价格计算器服务依赖于实体管理器:

my_namespace.price_calculator:
  class:     MyNamespace\PriceCalculator
  arguments: [ @doctrine.orm.default_entity_manager ]
Run Code Online (Sandbox Code Playgroud)

控制器使用价格计算器服务来获得价格:

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

    $unitPrice = $price->getUnitPrice();
    $totalPrice = $price->getTotalPrice();
    $optionsPrice = $price->getOptionsPrice();
}
Run Code Online (Sandbox Code Playgroud)

如果您需要请求或其他服务,您可以使用DIC注入它们或手动将其作为calculate()方法的参数.

请注意,我将EntityManager注入到PriceCalculator服务中,但您可以将数据提供程序定义为服务并将其注入(对于非常复杂的事情).

您还可以将所有查询推送到存储库并将实体传递给PriceCalculator.