Symfony 3 - 将控制器代码外包到服务层

时间:2016-07-13 08:22:55

标签: php dependency-injection doctrine-orm symfony

我在Symfony 3中很新,我想避免 我的控制器中的业务逻辑。 到目前为止我所做的是:

    <?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);
                }
            }
        }

我知道这不是好代码,因为所有业务逻辑都在控制器中。

但是我如何以及在哪里可以将这些代码(将请求设置为模型,持久化并与教义一起刷新等)到服务中或使用依赖注入?或者为此目的的服务不是正确的方式?

我知道这个页面和教程http://symfony.com/doc/current/best_practices/business-logic.html 但我不清楚在哪里放CRUD行动。 使用所有相关实体保存整个项目的一项服务?并使用Symfony \ Component \ HttpFoundation \ Request;在服务?那么把整个控制器代码放在我收到请求的地方并将模型分配到服务中? 感谢

1 个答案:

答案 0 :(得分:8)

更新2:I've extended this answer in a post。一定要检查一下!

更新:使用Symfony 3。3(2017年5月)与PSR-4 service autodiscovery 和PHP 7.1类型。

我将向您展示我如何在公司中讲授控制器存储库解耦

有两条简单的规则:

让我们将其应用于您的控制器

注意:这是伪代码,我没试过,但逻辑应该很容易理解。如果更改太多,只需检查步骤3和4.

我们解耦创建和保存过程。对于这两个实体。 这将引导我们提供4项服务:

# app/config/services.yml
services:
    _defaults:  
        autowire: true

    App\Domain\:
        resource: ../../App/Domain
    App\Repository\:
        resource: ../../App/Repository

1。产品工厂解耦创建过程

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

2。分销商产品工厂解耦创建流程

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

3。创建自己的ProductRepository服务

// 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();
    }
}

4。创建自己的DistributorProductRepository服务

// 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();
    }
}

5。我们用精美的控制器完成!

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

这就是全部!