Symfony / Doctrine:关于存储库注入的静态API设计和设计模式

时间:2018-08-06 07:18:48

标签: symfony doctrine-orm

我是Symfony的新手,这些问题是在最近的学习过程中提出的。

以一家商店为例,我将创建两个实体,即Product和Category,它们具有双向的多对一关系。

class Product
{
    private $id;
    private $name;
    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="products")
     * @ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=false)
     */
    private $category;
}

class Category
{
    private $id;
    private $name;
    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Product", mappedBy="category")
     */
    private $products;
}

所以我的第一个问题是:

如果要获取特定类别中的所有产品,URL应该为

  

/ categories?categoryId = 1&limit = 20&orderBy = name   (我知道这有点愚蠢,但是类别记录是否应包含所有产品信息?)

  

/ products?categoryId = 1&limit = 20&orderBy = name

对于后一个问题,出现第二个问题

我将ProductRepository注入到ProductController

class ProductController extends Controller
{
    private $productRepository;

    public function __construct(ProductRepository $productRepository)
    {
        $this->productRepository = $productRepository;
    }

    ...
}

为了将所有产品归为一个类别,我编写了这样的方法:

public function findByCategory(Category $category): array
{
    return $this->createQueryBuilder('p')
        ->andWhere('p.category = :category')
        ->setParameter('category', $category)
        ->orderBy('p.name', 'ASC')
        ->setMaxResults(20)
        ->getQuery()
        ->getResult()
    ;
}

因此,在ProductController中,如何从URL中的查询字符串'categoryId'获取Category对象?我应该同时注入CategoryRepository还是仅注入一个实体管理器对象?

2 个答案:

答案 0 :(得分:1)

Marco Pivetta aka Ocramius(该学说的主要开发者之一)说:

  

避免双向关联

     

双向关联是开销

     

仅对域逻辑工作所需的代码进行编码

     

使用复杂的DQL查询,而不是通过双向简化它们

所以也许 you don't need bi-directional association在这里。

对于您的第一个问题,我认为第二个解决方案更好:

  

/ products?categoryId = 1&limit = 20&orderBy = name

对于第二个问题,是的,如果要访问Category对象,则应注入CategoryRepository,即使可能,也请避免访问控制器中的整个entityManager。

您应该在控制器中注入服务。您的服务应公开公共方法,以通过data mappers对数据库执行定制的CRUD访问。请注意,repository不是数据映射器,而是

  

充当域和数据映射层之间的中介,就像内存中的域对象集合一样。

EAA目录的

P-马丁·福勒

Repositories are services实际上是很好的做法,可以将它们注入到控制器中。

有人捍卫这样的立场,即存储库不应包含创建更新删除,而只能包含 READ 。他们说这些操作使集合(可通过存储库访问)不一致。

这篇文章也可以提供帮助:How should a model be structured in MVC?

答案 1 :(得分:0)

对我来说,这里的问题是ORM在Symfony与数据库设计,建模和查询之间的作用非常明显的混淆。

在数据库中(使用PhpMyAdmin),您会注意到在产品表上有一列称为category(或category_id)的列。保持简单,要获得属于某个类别的产品,您只需要category_id。将这些知识带到Symfony,您不需要类别对象,只需使用从请求中获得的类别ID。另外,只需在控制器中使用EntityManager,不要使内容复杂化,特别是因为看来您才刚刚起步。

use Symfony\Component\HttpFoundation\Request;

class ProductController extends Controller
{
    public function get_product_from_categoryAction(Request $request)
    {
        $category_id = (int) $request->get('category');
        $limit = (int) $request->get('limit');
        $orderBy = strip_tags($request->get('orderBy'));

        $em = $this->getDoctrine()->getManager();
        $products = $em
            ->getRepository('AppBundle:Products')
            ->queryProductsByCategoryId($category_id, $limit, $orderBy);

    }

    ...
}

还有回购

public function queryProductsByCategoryId(int $category_id, int $limit = 10, string $orderBy = 'name')
{
    return $this->createQueryBuilder('p')
        ->andWhere('p.category = :category')
        ->setParameter('category', $category_id)
        ->orderBy('p.name', 'ASC')
        ->setMaxResults($limit)
        ->getQuery()
        ->getResult()
    ;
}

保持简单,然后,当您变得更高级时,请尝试一些更高级的东西。