Подтвердить что ты не робот

Symfony2/Doctrine, нужно поставить бизнес-логику в контроллер? И дублирующий контроллер?

У меня несколько сложный механизм ценообразования в моем приложении. Вот некоторые из моих бизнес-правил для настройки этапа (сущности полужирный):

  • Продукт может иметь уникальные Ценовые точки для данного Клиента, Веб-сайт или Клиента Группа.
  • Продукт может иногда иметь один или несколько дополнительных параметров, которые могут иметь свои собственные Ценовые точки или Правила цены. > .
  • Продукт имеет одно Уникальное дополнение, выбранное пользователем, которое по существу является ценой и целым числом.

Прямо сейчас у меня есть EntityRepository для Price Points, чтобы существенно определить правильную цену для базового продукта. То же самое относится к Уникальное дополнение и Параметры.

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/Doctrine, особенно в том, как доступ к Doctrine и Repositories осуществляется в контроллерах.

4b9b3361

Ответ 1

Вы правы, что у вас должна быть вся ваша повторно используемая бизнес-логика обработана службой, чтобы разные контроллеры могли повторно использовать код.

Вы проверили документацию "Как создать сервис":

Документация контейнерного контейнера

Я покажу вам скорость.

В 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 вы, возможно, уже блестели, это был путь!!

Надеюсь, это было по-прежнему полезно для вас!

Ответ 2

Вы упростили свой пример, поэтому я не знаю всех подробностей, но здесь мой вопрос, чтобы решить вашу проблему.

Обратите внимание, что вам может понадобиться больше одной службы, но вы должны получить идею на основе моего примера.

В основном следуйте принципу: у одного класса есть одна ответственность.

Калькулятор цен вычисляет цену:

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.