我的应用程序中有一些复杂的定价机制 - 以下是我设置阶段的一些业务规则(实体粗体):
现在,我有价格点的EntityRepository,从根本上确定基本产品的正确价格点。 唯一添加和选项也是如此。
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来根据存储库类中的业务逻辑来提取数据。
我很高兴地欢迎urwingit错误答案,因为我确实认为这是错误的。我该如何解决这个问题?美丽的东西将是一种服务,基本上是这样的:
$pricer = getPricerService->Pricer($Entities,$postdata,$etc);
$unitPrice = $pricer->getUnitPrice();
$totalPrice = $pricer->getTotalPrice();
$optionsPrice = $pricer->getOptionsPrice();
但我不知道如何在Symfony / Doctrine中执行此操作,尤其是在控制器中访问Doctrine和Repositories的方式。
答案 0 :(得分:29)
您应该将所有可重复使用的业务逻辑归结为服务,以便不同的控制器可以重复使用代码。
您是否查看了“如何创建服务”文档:
Service Container Documentation
我会尽快给你速度。
在config.yml中,您需要定义您的服务:
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');
还有其他方法可以模块化服务,例如不将所有服务转储到config.yml中,但所有这些都在文档中进行了解释。另请注意,您可以将任何其他服务注入您的服务,因此如果您需要arguments: [@doctrine, @security.context, @validator]
之类的内容,您可以完成所有这些工作,甚至:[@my_other_service]
。
我怀疑你注入EntityManager的其他问题,你可能已经知道这是可行的方法!
希望这对你有用!
答案 1 :(得分: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
}
}
价格由PriceInterface描述:
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 ]
控制器使用价格计算器服务来获取价格:
public function indexAction()
{
$priceCalculator = $this->get('my_namespace.price_calculator');
$price = $priceCalculator->calculate();
$unitPrice = $price->getUnitPrice();
$totalPrice = $price->getTotalPrice();
$optionsPrice = $price->getOptionsPrice();
}
如果您需要请求或其他服务,您可以使用DIC注入它们或手动将其作为 calculate()方法的参数注入。
请注意,我将 EntityManager 注入 PriceCalculator 服务,但您可以将数据提供程序定义为服务并将其注入(对于非常复杂的事情)。
您还可以将所有查询推送到存储库并将实体传递给 PriceCalculator 。