Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

README.md

Contributte / Nextras Criteria

Criteria pattern for Nextras ORM, inspired by Doctrine Criteria API.

Content

Installation

Install package using composer.

composer require contributte/nextras-criteria

Usage

Basic usage

use Contributte\Criteria\Criteria;
use Contributte\Criteria\Ordering;
use Contributte\Criteria\Nextras\CriteriaApplicator;

// Create criteria
$criteria = Criteria::create()
    ->where(Criteria::expr()->eq('status', 'active'))
    ->andWhere(Criteria::expr()->gt('age', 18))
    ->orderBy(Ordering::desc('createdAt'))
    ->setMaxResults(10);

// Apply to Nextras collection
$applicator = new CriteriaApplicator();
$users = $applicator->apply($orm->users->findAll(), $criteria);

Advanced usage

use Contributte\Criteria\Criteria;
use Contributte\Criteria\Ordering;
use Contributte\Criteria\Nextras\CriteriaApplicator;

class UserRepository
{
    private CriteriaApplicator $applicator;

    public function __construct(
        private UserOrmRepository $ormRepository,
    ) {
        $this->applicator = new CriteriaApplicator();
    }

    public function findActiveAdults(int $page, int $perPage): array
    {
        $criteria = Criteria::create()
            ->where(Criteria::expr()->andX(
                Criteria::expr()->eq('status', 'active'),
                Criteria::expr()->gte('age', 18),
                Criteria::expr()->isNotNull('verifiedAt')
            ))
            ->orderBy([
                Ordering::desc('createdAt'),
                Ordering::asc('lastName'),
            ])
            ->setFirstResult(($page - 1) * $perPage)
            ->setMaxResults($perPage);

        return $this->applicator
            ->apply($this->ormRepository->findAll(), $criteria)
            ->fetchAll();
    }
}

Expression Builder

The Criteria::expr() method returns an ExpressionBuilder for creating filter expressions.

Comparison operators

$expr = Criteria::expr();

// Equality
$expr->eq('name', 'John');           // name = 'John'
$expr->neq('status', 'deleted');     // status != 'deleted'

// Comparison
$expr->lt('age', 18);                // age < 18
$expr->lte('price', 100);            // price <= 100
$expr->gt('rating', 4);              // rating > 4
$expr->gte('quantity', 10);          // quantity >= 10

// IN / NOT IN
$expr->in('status', ['active', 'pending']);
$expr->notIn('role', ['banned', 'suspended']);

// LIKE patterns
$expr->contains('description', 'keyword');   // LIKE '%keyword%'
$expr->startsWith('email', 'admin@');        // LIKE 'admin@%'
$expr->endsWith('email', '@example.com');    // LIKE '%@example.com'

// NULL checks
$expr->isNull('deletedAt');
$expr->isNotNull('verifiedAt');

Composite expressions (AND/OR)

$expr = Criteria::expr();

// AND condition
$criteria = Criteria::create()->where(
    $expr->andX(
        $expr->eq('status', 'active'),
        $expr->gt('age', 18),
        $expr->isNotNull('email')
    )
);

// OR condition
$criteria = Criteria::create()->where(
    $expr->orX(
        $expr->eq('role', 'admin'),
        $expr->eq('role', 'moderator')
    )
);

// Nested conditions: (status = 'active' AND age > 18) OR role = 'admin'
$criteria = Criteria::create()->where(
    $expr->orX(
        $expr->andX(
            $expr->eq('status', 'active'),
            $expr->gt('age', 18)
        ),
        $expr->eq('role', 'admin')
    )
);

Fluent where methods

$criteria = Criteria::create()
    ->where(Criteria::expr()->eq('status', 'active'))
    ->andWhere(Criteria::expr()->gt('age', 18))
    ->orWhere(Criteria::expr()->eq('role', 'admin'));

Relationship traversal

Nextras ORM supports filtering by related entity properties using -> notation:

// Filter books by author's name
$criteria = Criteria::create()
    ->where(Criteria::expr()->eq('author->name', 'Jon Snow'));

// Order by related entity
$criteria = Criteria::create()
    ->orderBy(Ordering::asc('author->lastName'));

Ordering

use Contributte\Criteria\Ordering;

// Single ordering
$criteria = Criteria::create()
    ->orderBy(Ordering::desc('createdAt'));

// Multiple orderings
$criteria = Criteria::create()
    ->orderBy([
        Ordering::asc('lastName'),
        Ordering::asc('firstName'),
    ]);

// Add ordering
$criteria = Criteria::create()
    ->orderBy(Ordering::desc('priority'))
    ->addOrderBy(Ordering::asc('name'));

Pagination

$criteria = Criteria::create()
    ->setFirstResult(20)  // offset
    ->setMaxResults(10);  // limit

Examples

Reusable criteria

Create reusable criteria specifications:

class ActiveUserCriteria
{
    public static function create(): Criteria
    {
        return Criteria::create()
            ->where(Criteria::expr()->andX(
                Criteria::expr()->eq('status', 'active'),
                Criteria::expr()->isNull('deletedAt')
            ));
    }
}

// Combine criteria
$criteria = ActiveUserCriteria::create()
    ->andWhere(Criteria::expr()->gte('age', 18))
    ->orderBy(Ordering::desc('createdAt'));

Tip

Take a look at more examples in contributte/playground.