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

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


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!


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.