Symfony2/Doctrine, having to put business logic in my controller? And duplicating controller?

后端 未结 2 760
别那么骄傲
别那么骄傲 2020-12-31 01:37

I have a somewhat complex pricing mechanism in my application- Here are some of my business rules to set the stage (Entities are bolded):

  • A
相关标签:
2条回答
  • 2020-12-31 01:49

    You're correct that you should have all your re-usable business logic farmed off to a service so that different controllers can re-use the code.

    Have you checked out the "how to create a service" documentation:

    Service Container Documentation

    I'll give you the speed run-down though.

    In config.yml you need to define your service:

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

    Then you just need to make a bog standard PHP class to represent your service:

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

    Lastly to get your service from a controller you just need to do:

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

    There are other ways you can modularise the service such as not dumping all your services into config.yml but all of that is explained in the documentation. Also note that you can inject any other service you wish into your service so if you need stuff like arguments: [@doctrine, @security.context, @validator] you can do all that stuff or even: [@my_other_service].

    I suspect from your other question on injecting the EntityManager you may have already gleamed this was the way to go though!

    Hopefully this was still useful to you!

    0 讨论(0)
  • 2020-12-31 02:05

    You simplified your example so I don't really know all the details but here's my attemt to solve your problem.

    Note that you might actually need more then one service but you should get the idea based on my example.

    Basically follow the principle - One class has one responsobility.

    Price calculator calculates the Price:

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

    Price is described by the PriceInterface:

    namespace MyNamespace;
    
    interface PriceInterface
    {
        public function getUnitPrice();
    
        public function getTotalPrice();
    
        public function getOptionsPrice();
    }
    

    Price calculator service has a dependency on the entity manager:

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

    Controller uses price calculator service to get the price:

    public function indexAction() 
    {
        $priceCalculator = $this->get('my_namespace.price_calculator');
        $price = $priceCalculator->calculate();
    
        $unitPrice = $price->getUnitPrice();
        $totalPrice = $price->getTotalPrice();
        $optionsPrice = $price->getOptionsPrice();
    }
    

    If you need a Request or other service you can inject them using DIC or manually as a parameter to calculate() method.

    Note that I injected EntityManager to the PriceCalculator service but you might define data providers as services and inject them instead (for really complicated things).

    You could also push all queries to repositories and pass entities to your PriceCalculator.

    0 讨论(0)
提交回复
热议问题