2011-11-05 26 views
18

tengo un mecanismo de precios algo complejo en mi aplicación- Éstos son algunos de mis reglas de negocio para establecer la etapa (entidades están en negrita ):Symfony2/Doctrine, teniendo que poner la lógica de negocio en mi controlador? Y duplicar el controlador?

  • Un Producto pueden tener únicas puntos de precio para un Cliente, Sitio web, o Grupo de clientes.
  • Un Producto veces puede tener una o más opciones que pueden tener sus propios puntos de precio o reglas de precios.
  • A El producto tiene una Unique Addition seleccionada por el usuario, que es esencialmente un precio y un número entero.

En este momento, tengo una EntityRepository para puntos de precio para determinar esencialmente el punto de precio correcto para el producto base. Lo mismo ocurre con el Unique Addition y el Opciones.

PricePointRepository

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

Controlador (simplificado)

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 
} 

Eso es sólo para la página del producto. Qué sucede cuando llego al carro, guardo el pedido, etc., cuando esta lógica necesita ser reutilizada. Como puede ver, utilizo Doctrine para extraer datos en función de mi lógica empresarial en las clases de repositorio.

Agradezco gustosamente las respuestas de urdoingitwrong, porque realmente creo que esto está mal. ¿Cómo hago para arreglar esto? Algo hermoso sería un servicio que en esencia es la siguiente:

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

Pero no tengo ni idea de cómo hacer para hacer que el interior de Symfony/Doctrina, especialmente la forma en Doctrina y repositorios se accede en los controladores.

Respuesta

29

Tiene razón en que debe tener toda su lógica comercial reutilizable conectada a un servicio para que los diferentes controladores puedan reutilizar el código.

¿Ha revisado la documentación "cómo crear un servicio":

Service Container Documentation

Te daré la carrera hacia abajo la velocidad sin embargo.

En config.yml es necesario definir su servicio:

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

A continuación, sólo tiene que hacer una clase PHP porquerías estándar para representar a su servicio:

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. 
} 

último para obtener su servicio desde un controlador sólo necesita do:

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

Hay otras maneras en que puede modularizar el servicio como no echando todos sus servicios en config.yml pero todo eso se explica en la documentación. También tenga en cuenta que puede inyectar cualquier otro servicio que desee en su servicio, así que si necesita cosas como arguments: [@doctrine, @security.context, @validator] puede hacer todas esas cosas o incluso: [@my_other_service].

Sospecho que por su otra pregunta sobre cómo inyectar el EntityManager es posible que ya haya brillado, ¡esta era la manera de hacerlo!

¡Espero que esto todavía sea útil para usted!

+0

Fantástico, ¡gracias! Entre su respuesta y la de Kuba tengo una idea de cómo lograr esta parte de la aplicación. – Nick

+0

¿Qué sucede si quiere combinar dos llamadas de servicio en la misma transacción? – GorillaApe

10

Ha simplificado su ejemplo, así que realmente no sé todos los detalles, pero aquí está mi intento de resolver su problema.

Tenga en cuenta que en realidad podría necesitar más de un servicio, pero debería obtener la idea en función de mi ejemplo.

Básicamente, siga el principio: una clase tiene una capacidad de respuesta.

calculadora Precio calcula el precio:

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 
    } 
} 

precio es descrito por el PriceInterface:

namespace MyNamespace; 

interface PriceInterface 
{ 
    public function getUnitPrice(); 

    public function getTotalPrice(); 

    public function getOptionsPrice(); 
} 

servicio Calculadora de precio tiene una dependencia en el gestor de entidades:

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

Controlador utiliza el servicio de calculadora de precios para obtener el precio:

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

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

Si necesita una solicitud u otro servicio que puede inyectarles usando DIC o manualmente como parámetro para calcular () método.

Tenga en cuenta que Inyecté EntityManager a la PriceCalculator servicio pero es posible definir los proveedores de datos como servicios e inyectarlos en su lugar (por cosas muy complicadas).

También puede enviar todas las consultas a repositorios y pasar entidades a su PriceCalculator.

+0

Esto, combinado con la respuesta de Kasheen, fue muy útil. ¡Gracias! – Nick

Cuestiones relacionadas