Repository

在上一章,所有的查询是直接写在你的测试用例的方法中的。但对于程序的组织来说,为了隔离,复用和测试这些查询 Doctrine 提供了一个专门的 repository 类,它允许你保存所有查询逻辑到一个中心位置。

所有的 repository 类,都应该放到 Bundle 的 Repositories 文件夹中。

要定义repository类,有两种方法。

一、在实体类中添加 repository 类的声明:

// src/DemoBundle/Entities/Product.php
<?php
namespace DemoBundle\Entities;

use Doctrine\ORM\Mapping as ORM;
/**
 * @ORM\Entity
 * @ORM\Table(name="products")
 * @ORM\Entity(repositoryClass="DemoBundle\Repositories\ProductRepository")
 */
class Product
{
    //...
}

新建 Repositories 文件夹,在 Repositories 下新建 ProductRepository 类:

//src/DemoBundle/Repositories/ProductRepository.php
<?php
namespace DemoBundle\Repositories;

use Doctrine\ORM\EntityRepository;


class ProductRepository extends EntityRepository
{
    public function findAllOrderedByName()
    {
        return $this->getEntityManager()
            ->createQuery(
                'SELECT p FROM DemoBundle\Entities\Product p ORDER BY p.name ASC'
            )
            ->getResult();
    }
}

在 Repository 类中可以通过 $this->getEntityManager() 方法类获取entity管理。

你就可以像使用默认的方法一样使用这个新定义的方法了:

//src/DemoBundle/Tests/ProductTest.php
/**
 * A basic test example.
 *
 * @return void
 */
public function testProductRepository()
{
    //这一行取出了Doctrine的 entity manager 对象,它负责处理数据库的持久化(写入)和取出对象的过程。
    $em = app('registry')->getManager('default');

    $productRepository = $em->getRepository(Product::class);

    $products = $productRepository->findAllOrderedByName();

    $this->assertEquals(count($productRepository->findAll()), count($products));
}

当使用一个自定义的 repository 类时,你依然可以访问原有的默认查找方法,比如find() 和findAll()等。

使用注解的方式 Doctrine 会在调用 $em->getRepository(Product::class); 时,通过实体的注解找到实体对应的 repository 类。这种方式是 Doctrine 默认提供的,其有一个确定就是:这样定义一个实体只能有一个 repository ,将程序所有自定义查询都放到一个类里面,随着项目的发展,势必会导致 repository 类的肥大。这显然违反 SOLID 的单一职责原则。

二、通过在 repository 类中声明关联的实体

与第一种方法相反,这种方式是通过在 repository 类中声明所关联的实体,来实现 repository 类的声明。由于 repository 类初始化时,需要传入Entity Manager 和实体类的 ClassMate,为了方便初始化 repository 类,需要引入一个 Traits 。

在 Repositories 文件夹下新建一个 ProductPriceRepository 类,用来处理价格相关的查询 :

//src/DemoBundle/Repositories/ProductPriceRepository.php
<?php
namespace DemoBundle\Repositories;

use Doctrine\ORM\EntityRepository;
use EspierBundle\Traits\RepositoryFactory;
use DemoBundle\Entities\Product;

class ProductPriceRepository extends EntityRepository
{
    public static $entityClass = Product::class;

    use RepositoryFactory;

    public function findAllOrderedByName()
    {
        return $this->getEntityManager()
            ->createQuery(
                'SELECT p FROM DemoBundle\Entities\Product p ORDER BY p.name ASC'
            )
            ->getResult();
    }
}

使用方式如下:

//src/DemoBundle/Tests/ProductTest.php

use DemoBundle\Repositories\ProductPriceRepository;

    //...

    public function testProductPriceRepository()
    {
        $productRepository = ProductPriceRepository::instance();

        $products = $productRepository->findAllOrderedByName();

        $this->assertEquals(count($productRepository->findAll()), count($products));
    }

Last updated