Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ttskch/doctrine-orm-criteria
Doctrine ORM Criteria allows you to separate any complex "search condition" as a Criteria with a specialized API for QueryBuilder of doctrine/orm.
https://github.com/ttskch/doctrine-orm-criteria
criteria doctrine doctrine-orm symfony
Last synced: 3 months ago
JSON representation
Doctrine ORM Criteria allows you to separate any complex "search condition" as a Criteria with a specialized API for QueryBuilder of doctrine/orm.
- Host: GitHub
- URL: https://github.com/ttskch/doctrine-orm-criteria
- Owner: ttskch
- License: mit
- Created: 2024-08-21T13:25:02.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2024-08-27T12:19:40.000Z (5 months ago)
- Last Synced: 2024-09-29T17:21:17.042Z (4 months ago)
- Topics: criteria, doctrine, doctrine-orm, symfony
- Language: PHP
- Homepage: https://packagist.org/packages/ttskch/doctrine-orm-criteria
- Size: 44.9 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Doctrine ORM Criteria
[![](https://github.com/ttskch/doctrine-orm-criteria/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/ttskch/doctrine-orm-criteria/actions/workflows/ci.yaml?query=branch:main)
[![codecov](https://codecov.io/gh/ttskch/doctrine-orm-criteria/graph/badge.svg?token=gu1GDphBHg)](https://codecov.io/gh/ttskch/doctrine-orm-criteria)
[![Latest Stable Version](https://poser.pugx.org/ttskch/doctrine-orm-criteria/v)](https://packagist.org/packages/ttskch/doctrine-orm-criteria)
[![Total Downloads](https://poser.pugx.org/ttskch/doctrine-orm-criteria/downloads)](https://packagist.org/packages/ttskch/doctrine-orm-criteria/stats)## Motivation
[`QueryBuilder`](https://www.doctrine-project.org/projects/doctrine-orm/en/2.20/reference/query-builder.html) of [doctrine/orm](https://www.doctrine-project.org/projects/doctrine-orm/en/2.20/index.html) has a method called [`addCriteria()`](https://www.doctrine-project.org/projects/doctrine-orm/en/2.20/reference/query-builder.html#adding-a-criteria-to-a-query) that allows you to build queries by combining [`Criteria`](https://www.doctrine-project.org/projects/doctrine-orm/en/2.20/reference/working-with-associations.html#filtering-collections) of [doctrine/collections](https://www.doctrine-project.org/projects/doctrine-collections/en/stable/index.html). This allows you to separate the concerns of "search conditions" into a `Criteria`, improving the maintainability of your codebase.
However, `Criteria` of doctrine/collections only has a very limited matching language because it is designed to work both on the SQL and the PHP collection level, and therefore cannot be used to build complex queries.
Rejoice! **Doctrine ORM Criteria** allows you to separate any complex "search condition" as a `Criteria` with a specialized API for `QueryBuilder` of doctrine/orm just like below.
```php
$qb = (new CriteriaAwareness($fooRepository->createQueryBuilder('f')))
->addCriteria(new IsPublic(), 'f')
->addCriteria(new IsAccessibleBy($user), 'f')
->addCriteria(new CategoryIs($category), 'f')
->addCriteria(new OrderByRandom(), 'f')
->getQueryBuilder()
;
$foos = $qb->getQuery()->getResult();// Or, using the Repository integration:
$foos = $fooRepository->findByCriteria([
new IsPublic(),
new IsAccessibleBy($user),
new CategoryIs($category),
new OrderByRandom(),
]);
``````php
final readonly class IsPublic implements CriteriaInterface
{
public ?\DateTimeInterface $at;public function __construct(?\DateTimeInterface $at = null)
{
$this->at = $at ?? new \DateTimeImmutable();
}public function apply(QueryBuilder $qb, string $alias): void
{
$qb
->andWhere("$alias.state = :state")
->andWhere($qb->expr()->andX(
$qb->expr()->orX(
"$alias.openedAt IS NULL",
"$alias.openedAt <= :at",
),
$qb->expr()->orX(
"$alias.closedAt IS NULL",
"$alias.closedAt > :at",
),
))
->setParameter('state', Foo::STATE_PUBLIC)
->setParameter('at', $this->at)
;
}
}
```## Requirements
* PHP: ^8.0
* Doctrine ORM: ^2.8> Support for Doctrine ORM v3 is coming soon.
## Installation
```shell
$ composer require ttskch/doctrine-orm-criteria
```## Usage
### Basic
You can create your own `Criteria` by implementing [`CriteriaInterface`](src/Criteria/CriteriaInterface.php) and adding it to [`CriteriaAwareness`](src/CriteriaAwareness.php) to build queries.
```php
use App\Repository\Criteria\Foo\IsPublic;
use Ttskch\DoctrineOrmCriteria\CriteriaAwareness;$qb = (new CriteriaAwareness($fooRepository->createQueryBuilder('f')))
->addCriteria(new IsPublic(), 'f')
->getQueryBuilder()
;
``````php
at = $at ?? new \DateTimeImmutable();
}public function apply(QueryBuilder $qb, string $alias): void
{
$qb
->andWhere("$alias.state = :state")
->andWhere($qb->expr()->andX(
$qb->expr()->orX(
"$alias.openedAt IS NULL",
"$alias.openedAt <= :at",
),
$qb->expr()->orX(
"$alias.closedAt IS NULL",
"$alias.closedAt > :at",
),
))
->setParameter('state', Foo::STATE_PUBLIC)
->setParameter('at', $this->at)
;
}
}
```### Built-in Criteria and utilities
There are some built-in `Criteria`: `OrderBy`, `Andx`, and `Orx`. Using `Andx` and `Orx`, you can combine multiple `Criteria` to create a new `Criteria`.
```php
at = $at ?? new \DateTimeImmutable();
}public function apply(QueryBuilder $qb, string $alias): void
{
(new Andx([
new Orx([
new IsPublic($this->at),
...array_map(fn (string $category) => new CategoryIs($category), Foo::PUBLIC_CATEGORIES),
]),
new IsAccessibleBy($this->me),
]))->apply($qb, $alias);
}
}
```Additionally, when creating your own `Criteria`, you can use [`AddSelectTrait`](src/Criteria/Traits/AddSelectTrait.php) and [`JoinTrait`](src/Criteria/Traits/JoinTrait.php) to ensure that the `addSelect()` and `join` are IDEMPOTENT even if the `Criteria` is applied multiple times to the `QueryBuilder`.
```php
leftJoin($qb, sprintf('%s.user', $alias), $userAlias);$qb
->andWhere(sprintf('%s = :user', $userAlias))
->setParameter('user', $this->me)
;
}
}
```### Integration with Repository
You can also easily integrate with your repositories using [`CriteriaAwareRepositoryTrait`](src/Repository/CriteriaAwareRepositoryTrait.php).
```diff
*/
class FooRepository extends ServiceEntityRepository
{
+ /** @use CriteriaAwareRepositoryTrait */
+ use CriteriaAwareRepositoryTrait;
+
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Foo::class);
}
}
``````php
$foos = $fooRepository->findByCriteria([
new IsPublic(),
new IsAccessibleBy($user),
new CategoryIs($category),
new OrderByRandom(),
]);\PHPStan\dumpType($foos); // Dumped type: array
$foo = $fooRepository->findOneByCriteria([
new IsPublic(),
new IsAccessibleBy($user),
new CategoryIs($category),
new OrderByRandom(),
]);\PHPStan\dumpType($foo); // Dumped type: App\Entity\Foo|null
$count = $fooRepository->countByCriteria([
new IsPublic(),
new IsAccessibleBy($user),
new CategoryIs($category),
]);\PHPStan\dumpType($count); // Dumped type: int
```## Getting involved
```shell
$ composer install# Develop...
$ composer tests
```