demos-europe/edt-dql

扩展 demos-europe/edt-queries,以 Doctrine ORM 作为数据源。


README

通过支持 Doctrine ORM 扩展 edt/queries

同时作为 Doctrine ORM 的辅助库,用于生成 DQL 查询。目前,重点在于从给定的属性路径检测连接子句,以排序和过滤结果集。

假设用户对 Doctrine ORM 有基本了解才能使用此库。

示例

假设我们有一个 BookPersonAddress 实体。

Book 有一个 author 属性,它引用了 Person 实体。

Person 有一个 birth 属性,其中包含有关出生地和日期的信息。

Birth 实体有一个 country 属性,它是一个字符串。

目标是获取所有作者出生在美国的 Book 实体。这可以通过首先从数据库中获取所有实体并在 PHP 中过滤结果来实现。但从性能和内存的角度来看,在数据库中执行过滤更合理。

使用 DQL,我们可以创建一个查询,包含两个连接来获取所需的结果

use \Tests\data\DqlModel\Book;
$queryBuilder = $this->getEntityManager()->createQueryBuilder()
    ->select('Book')
    ->from(Book::class, 'Book')
    ->leftJoin('Book.author', 'Person')
    ->leftJoin('Person.birth', 'Birth')
    ->where('Birth.country = :countryName')
    ->setParameter('countryName', 'USA');

此库可以从以下代码生成类似的查询构建器

use \Tests\data\DqlModel\Book;
use EDT\DqlQuerying\ConditionFactories\DqlConditionFactory;
use \EDT\DqlQuerying\Utilities\QueryBuilderPreparer;
/** @var \Doctrine\ORM\EntityManager $entityManager */
$entityManager = $this->getEntityManager();
$conditionFactory = new DqlConditionFactory();
$metadataFactory = $entityManager->getMetadataFactory();

$builderPreparer = new QueryBuilderPreparer(Book::class, $metadataFactory, new JoinFinder($metadataFactory));
$builderPreparer->setWhereExpressions([
    $conditionFactory->propertyHasValue('USA', 'authors', 'birth', 'country'),
]);

$builderPreparer->fillQueryBuilder($entityManager->createQueryBuilder());

第二个版本的主要优势不在于行数或可读性,而在于无需手动详细指定查询。这允许动态接收查询并直接在数据库中执行(前提是在之前检查了授权和验证)。

条件

除了上面显示的 PropertyHasValue 之外,还支持更多条件类型。所有由库提供的条件都可以通过使用 DqlConditionFactory 类找到和创建。

如果提供的条件不足以满足需要,您可以编写自己的子句,通过实现 ClauseInterface

条件嵌套

可以使用 ANDOR 连接词将条件组合在一起

$conditionFactory = new EDT\DqlQuerying\ConditionFactories\DqlConditionFactory();
$andConditions = [ /* ... */];
$orConditions = [ /* ... */];
$orCondition = $conditionFactory->anyConditionApplies(...$orConditions);
$nestedCondition = $conditionFactory->allConditionsApply(...$andConditions);

排序

定义排序的方法与定义条件的方法类似。在以下示例中,书籍将按作者姓名作为第一优先级进行排序,作者出生日期作为第二优先级。

use EDT\DqlQuerying\ConditionFactories\DqlConditionFactory;
use EDT\DqlQuerying\SortMethodFactories\SortMethodFactory;
use \Tests\data\DqlModel\Book;
use EDT\DqlQuerying\Utilities\QueryBuilderPreparer;
/** @var \Doctrine\ORM\EntityManager $entityManager */
$entityManager = $this->getEntityManager();
$conditionFactory = new DqlConditionFactory();
$sortingFactory = new SortMethodFactory();
$metadataFactory = $entityManager->getMetadataFactory();

$builderPreparer = new QueryBuilderPreparer(Book::class, $metadataFactory, new JoinFinder($metadataFactory));
$builderPreparer->setSelectExpressions([
    $sortingFactory->propertyAscending('authors', 'name'),
    $sortingFactory->propertyDescending('authors', 'birthdate'),
]);

$builderPreparer->fillQueryBuilder($entityManager->createQueryBuilder());

如果提供的排序实现不足以满足需要,您可以编写自己的排序实现

致谢和认可

由 Christian Dressler 担任概念和实现,感谢 eFrane