I am very new in Symfony 3 and I want to avoid the business logic in my controllers. What I have done so far is this:
<?php
namespace RestBundle\Controller;
use RestBundle\Entity\Attribute;
use RestBundle\Entity\DistributorProduct;
use RestBundle\Entity\AttributeValue;
use RestBundle\Entity\ProductToImage;
use Symfony\Component\HttpFoundation\Request;
use RestBundle\Entity\Product;
use FOS\RestBundle\Controller\FOSRestController;
/**
* Product controller.
*
*/
class ProductController extends FOSRestController
{
/**
* Creates a new Product entity.
*
*/
public function createProductAction(Request $request)
{
// Doctrine Manager
$em = $this->getDoctrine()->getManager();
// todo: get the logged in distributor object
$distributor = $em->getRepository('RestBundle:Distributor')->find(1);
// Main Product
$product = new Product();
$product->setEan($request->get('ean'));
$product->setAsin($request->get('asin'));
$em->persist($product);
// New Distributor Product
$distributorProduct = new DistributorProduct();
$distributorProduct->setDTitle($request->get('title'));
$distributorProduct->setDDescription($request->get('description'));
$distributorProduct->setDPrice($request->get('price'));
$distributorProduct->setDProductId($request->get('product_id'));
$distributorProduct->setDStock($request->get('stock'));
// Relate this distributorProduct to the distributor
$distributorProduct->setDistributor($distributor);
// Relate this distributorProduct to the product
$distributorProduct->setProduct($product);
$em->persist($distributorProduct);
// Save it
$em->flush();
$response = $em->getRepository('RestBundle:Product')->find($product->getUuid());
return array('product' => $response);
}
}
}
I know that this is not good code because all the business logic is in the controller.
But how and where can I put this code (set requests into model, persist and flush with doctrine, etc) into a service or use dependency injection for it? Or is service for this purpose not the right way?
I know this page and tutorial http://symfony.com/doc/current/best_practices/business-logic.html but it is not clearify for me where to put CRUD Actions. Do ONE service for save a whole project with all the related entities? And use the Symfony\Component\HttpFoundation\Request; in a service? So put the whole controller code where I get the request and assign to the models into a service? Thanks
UPDATE 2: I've extended this answer in a post. Be sure to check it!
UPDATE: use Symfony 3.3 (May 2017) with PSR-4 service autodiscovery and PHP 7.1 types.
I will show you how I lecture controller repository decoupling in companies.
There are 2 simple rules:
new
in the controller (static, non-DI approach) (there is now also Sniff for that)Let's apply this to your controller
Note: this is pseudo code, I haven't tried that, but the logic should be easy to understand. If this is too many change, just check the steps 3 and 4.
We decouple create and save process. For both entities. This will lead us to 4 services:
1. Product Factory to decouple create process
2. Distributor Product Factory to decouple create process
3. Create own ProductRepository service
4. Create own DistributorProductRepository service
5. And we finish with nice and thin controller!
That's all!