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