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)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:
# app/config/services.yml
services:
_defaults:
autowire: true
App\Domain\:
resource: ../../App/Domain
App\Repository\:
resource: ../../App/Repository
// ProductFactory.php
namespace App\Domain\Product;
final class ProductFactory
{
public function createFromRequest(Request $request): Product
{
$product = new Product();
$product->setEan($request->get('ean'));
$product->setAsin($request->get('asin'));
return $product;
}
}
// DistributorProductFactory.php
namespace App\Domain\Product;
final class DistributorProductFactory
{
public function createFromRequestProductAndDistributor(
Request $request,
Product $product,
Distributor $distributor
): DistributorProduct {
$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 product
$distributorProduct->setProduct($product);
// Relate this distributorProduct to the product
$distributorProduct->setDistributor($distributor);
return $distributorProduct;
}
}
// ProductRepository.php
namespace App\Repository;
use RestBundle\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;
final class ProductRepository
{
/**
* @var EntityManagerInterface
*/
private $entityManager;
public funtion __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function save(Product $product): void
{
$this->entityManager->persist($product);
$this->entityManager->flush();
}
}
// DistributorProductRepository.php
namespace App\Repository;
use RestBundle\Entity\DistributorProduct;
use Doctrine\ORM\EntityManagerInterface;
final class DistributorProductRepository
{
/**
* @var EntityManagerInterface
*/
private $entityManager;
public funtion __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function save(DistributorProduct $distributorProduct): void
{
$this->entityManager->persist($distributorProduct);
$this->entityManager->flush();
}
}
namespace RestBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use FOS\RestBundle\Controller\FOSRestController;
final class ProductController extends FOSRestController
{
// get here dependencies via constructor
public function createProductAction(Request $request): array
{
// todo: get the logged in distributor object
$distributor = $em->getRepository('RestBundle:Distributor')->find(1);
$product = $this->productFactory->createFromRequest($request);
$distributorProduct = $this->distributorProductFactory->createFromRequestProductAndDistributor(
$request,
$product,
$distributor
);
$this->productRepository->save($product);
$this->distributorProductRepository->save($product);
return [
'product' => $product
];
}
}
That's all!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With