model-view-controller - para - error al ejecutar el generador de codigo seleccionado no se pueden recuperar metadatos
¿Symfony2/Doctrine, tener que poner lógica empresarial en mi controlador? ¿Y duplicando el controlador? (2)
Tengo un mecanismo de precios algo complejo en mi aplicación. Aquí están algunas de mis reglas comerciales para establecer el escenario (las entidades están en negrita ):
- Un producto puede tener puntos de precio únicos para un determinado cliente , sitio web o grupo de clientes .
- Un producto a veces puede tener una o más opciones adicionales que pueden tener sus propios puntos de precio o reglas de precio .
- Un Producto tiene una Adición Única seleccionada por el usuario, que es esencialmente un precio y un entero.
En este momento, tengo un EntityRepository para puntos de precio para determinar esencialmente el punto de precio correcto para el producto base. Lo mismo ocurre con la adición única y las 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, guardando el pedido, etc., cuando esta lógica necesita ser reutilizada. Como puede ver, uso Doctrine a lo largo de toda la lógica de negocios en las clases del repositorio.
Con mucho gusto doy la bienvenida a las respuestas urdoingitwrong, porque realmente creo que esto está mal. ¿Cómo hago para arreglar esto? Algo hermoso sería un servicio que esencialmente es así:
$pricer = getPricerService->Pricer($Entities,$postdata,$etc);
$unitPrice = $pricer->getUnitPrice();
$totalPrice = $pricer->getTotalPrice();
$optionsPrice = $pricer->getOptionsPrice();
Pero no tengo idea de cómo hacerlo en Symfony / Doctrine, especialmente la forma en que se accede a Doctrine y Repositories en los Controladores.
Tiene razón en que debe tener toda su lógica empresarial reutilizable agrupada en un servicio para que diferentes controladores puedan reutilizar el código.
¿Has revisado la documentación de "cómo crear un servicio"?
Documentación del contenedor de servicios
Sin embargo, te daré la reducción de velocidad.
En config.yml necesitas definir tu servicio:
services:
pricing_service:
class: Acme/ProductBundle/Service/PricingService
arguments: [@doctrine]
Entonces, solo necesita crear una clase estándar de PHP para representar 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.
}
Por último, para obtener su servicio de un controlador que solo necesita hacer:
$pricingService = $this->get(''pricing_service'');
Hay otras formas en que puede modularizar el servicio, como no descargar 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, por lo que si necesita elementos como arguments: [@doctrine, @security.context, @validator]
puede hacer todo eso o incluso: [@my_other_service]
.
Sin embargo, sospecho que por su otra pregunta sobre la inyección del EntityManager, ¡es posible que ya haya dicho que este era el camino a seguir!
¡Ojalá esto te haya sido útil!
Usted simplificó su ejemplo, así que no conozco todos los detalles, pero aquí está mi intento de resolver su problema.
Tenga en cuenta que es posible que necesite más de un servicio, pero debería tener una idea basada en mi ejemplo.
Básicamente, siga el principio: una clase tiene una responsabilidad.
Calculadora de 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
}
}
El precio es descrito por el PriceInterface:
namespace MyNamespace;
interface PriceInterface
{
public function getUnitPrice();
public function getTotalPrice();
public function getOptionsPrice();
}
El servicio de calculadora de precios depende del administrador de la entidad:
my_namespace.price_calculator:
class: MyNamespace/PriceCalculator
arguments: [ @doctrine.orm.default_entity_manager ]
El controlador utiliza el servicio de cálculo 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, puede inyectarlos utilizando DIC o manualmente como un parámetro para calcular () .
Tenga en cuenta que inyecté EntityManager en el servicio PriceCalculator , pero puede definir proveedores de datos como servicios e inyectarlos en su lugar (para cosas realmente complicadas).
También puede enviar todas las consultas a los repositorios y pasar las entidades a su PriceCalculator .