PHPackages                             demos-europe/edt-queries - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. demos-europe/edt-queries

ActiveLibrary

demos-europe/edt-queries
========================

Eases querying entities via property paths.

0.26.0(1y ago)222.3k↓21.4%4MITPHPPHP ^8.1

Since Jun 23Pushed 1y ago1 watchersCompare

[ Source](https://github.com/demos-europe/edt-queries)[ Packagist](https://packagist.org/packages/demos-europe/edt-queries)[ RSS](/packages/demos-europe-edt-queries/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (1)Versions (111)Used By (4)

This composer library provides PHP classes to ease the access to a wanted list of entities for common use cases while being agnostic about the source of the entities.

Overview
--------

[](#overview)

### Property path based approach

[](#property-path-based-approach)

Two common requirements when fetching a list of entities are to 1) limit it to entities matching specific conditions and 2) sort it using specific sort methods.

Different query languages handle these requirements in different scopes and manners. EDT-Queries allows the usage of paths when accessing entity properties. This eases the creation of queries, as no manual joins like in SQL need to be defined and allows to focus on the actual intention instead of the implementation details of the data source. On the other hand this adds some requirements regarding the relationship between entities: to fetch books by the name of their authors, the book entity must reference the author entity. Likewise, to fetch authors by the title of their books, the author entity must reference the book entity.

While a bidirectional relationship between books and authors seems reasonable, this drawback becomes more apparent in cases where a unidirectional relationship would have been sufficient normally. Suppose you have a separate entity for E-mail addresses which is referenced by different entities like "organisation", "person" and "block list". Using EDT-Queries to simply get all e-mail addresses that are still in use would require the e-mail address entity to have a relationship to each of these three entities.

### Data source agnostic

[](#data-source-agnostic)

When creating a query using EDT-Queries the thought model is based on entities with properties and relationships to other entities. If that thought model can be converted to the model of the backing data source, then support for the backing data source is possible to implement.

For example when fetching books by their author’s name we may use a condition equivalent to `book.getAuthor().getName() === $authorName` (the actual syntax to create conditions is shown later). If `book` and `author` exist as tables in a relational database, then in principle this expression can be converted into a SQL query with a `JOIN` between `book` and `author` and a `WHERE` condition to compare the actual author’s name to the given author’s name.

Implementations for specific data sources are mostly separated from this project. See [Providers and factories setup](#provider-factory-setup) for additional information.

### Usage examples

[](#usage-examples)

In the following examples we get all books by authors born after the year 1800 whose last name start with 'A', primarily sorted by the name of their publishing company and secondarily sorted by their publication date.

As this example focuses on the usage only, we use placeholders for the factories and the provider, instead of actually initializing them. A possible setup is shown in [Providers and factories setup](#provider-factory-setup).

```
use EDT\ConditionFactory\ConditionFactoryInterface;
use EDT\Querying\Contracts\ObjectProviderInterface;
use EDT\Querying\Contracts\SortMethodFactoryInterface;

// Placeholder setup: The actual factory and provider instances depend on the type of data source.
/** @var ConditionFactoryInterface $conditionFactory */
/** @var SortMethodFactoryInterface $sortMethodFactory */
/** @var ObjectProviderInterface $bookProvider */

// Query definition
$nameCondition = $conditionFactory->propertyStartsWithCaseInsensitive('A', 'author', 'lastName');
$birthDateCondition = $conditionFactory->valueGreaterThan(1800, 'author', 'birth', 'year');
$primarySortMethod = $sortMethodFactory->propertyAscending('publisher', 'name');
$secondarySortMethod = $sortMethodFactory->propertyDescending('publishDate');
$conditions = [$nameCondition, $birthDateCondition];
$sortMethods = [$primarySortMethod, $secondarySortMethod];

// Executing the query
$booksResultList = $bookProvider->getObjects($conditions, $sortMethods);
```

As an alternative the above can be written as fluent query as shown below.

```
use EDT\ConditionFactory\ConditionFactoryInterface;
use EDT\Querying\Contracts\ObjectProviderInterface;
use EDT\Querying\Contracts\SortMethodFactoryInterface;
use EDT\Querying\FluentQueries\FluentQuery;
use EDT\Querying\FluentQueries\ConditionDefinition;
use EDT\Querying\FluentQueries\SortDefinition;
use EDT\Querying\FluentQueries\SliceDefinition;

// Query definition
$query = create_book_query();
$query->getConditionDefinition()
    ->propertyStartsWithCaseInsensitive('A', 'author', 'lastName')
    ->valueGreaterThan(1800, 'author', 'birth', 'year');
$query->getSortDefinition()
    ->propertyAscending('publisher', 'name')
    ->propertyDescending('publishDate');

// Executing the query
$bookResultList = $query->getEntities();

// Placeholder setup: The actual factory and provider instances depend on the type of data source.
function create_book_query(): FluentQuery
{
    /** @var ConditionFactoryInterface $conditionFactory */
    /** @var SortMethodFactoryInterface $sortMethodFactory */
    /** @var ObjectProviderInterface $bookProvider */

    return new FluentQuery(
        $bookProvider,
        new ConditionDefinition($conditionFactory),
        new SortDefinition($sortMethodFactory),
        new SliceDefinition()
    );
}
```

### Providers and factories setup

[](#providers-and-factories-setup)

Which implementations to use for the `ConditionFactoryInterface`, `SortMethodFactoryInterface` and `ObjectProviderInterface` depends on your actual data source.

Please note that factories and object providers for different data sources can only be used in a mix and match manner under specific requirements. To be specific: to access a data source via an object provider not only the object provider must support the data source but the factories from which the conditions and sort methods were created too.

To keep this projects dependencies small, EDT-Queries only supports a single data source, namely an already loaded PHP `array`providing the entity objects.

An implementation for the [Doctrine ORM](https://www.doctrine-project.org/projects/orm.html) has already been written and is available as [EDT-DQL](https://github.com/demos-europe/EDT-DQL). It provides factories for conditions and sort methods that are automatically converted into DQL, which in turn already supports a multitude of different data sources.

#### PHP array data source

[](#php-array-data-source)

Even though their real-world use cases are limited, the `array`-based approach can still be used on small data sets, that can be loaded into an array. To complete the example above you could instantiate a `PhpConditionFactory` and a `PhpSortMethodFactory` to create the corresponding instances. When creating the `PrefilledObjectProvider` you need to inject the `PropertyAccessorInterface`dependency, which determines how values are read from the entities when applying conditions and sort methods. This allows to adjust the behavior of the provider without the need to completely extend it and override its methods.

```
// The books to be filtered, preloaded into an array
/** @var list $books */

// Setting up the factories and provider
$conditionFactory = new \EDT\Querying\ConditionFactories\PhpConditionFactory();
$sortMethodFactory = new EDT\Querying\SortMethodFactories\PhpSortMethodFactory();
$bookProvider = new \EDT\Querying\ObjectProviders\PrefilledObjectProvider(
    new \EDT\Querying\PropertyAccessors\ReflectionPropertyAccessor(),
    $books
);

// Filtering books by the name of the auther's children and sorting them by their title
$bookProvider->getObjects(
    [$conditionFactory->propertyHasValue('Christopher Tolkien', 'author', 'children' 'name')],
    [$sortMethodFactory->propertyAscending('title')]
);
```

Credits and acknowledgements
----------------------------

[](#credits-and-acknowledgements)

Conception and implementation by Christian Dressler with many thanks to [eFrane](https://github.com/eFrane).

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance41

Moderate activity, may be stable

Popularity30

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 98.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~9 days

Recently: every ~119 days

Total

110

Last Release

385d ago

PHP version history (5 changes)0.6.1PHP &gt;=7.3,&lt;8.2

0.8.0PHP &gt;=7.3,&lt;8

0.13.0PHP &gt;=7.4,&lt;8

0.14.1PHP ^7.4 || ^8.0

0.17.5PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/b2998f0a3cfbccb2c469bde14aa00b8f61fb12380a7785213927cbaf033e4f12?d=identicon)[demosci](/maintainers/demosci)

---

Top Contributors

[![actions-user](https://avatars.githubusercontent.com/u/65916846?v=4)](https://github.com/actions-user "actions-user (93 commits)")[![graupnerdemos](https://avatars.githubusercontent.com/u/40465804?v=4)](https://github.com/graupnerdemos "graupnerdemos (1 commits)")

### Embed Badge

![Health badge](/badges/demos-europe-edt-queries/health.svg)

```
[![Health](https://phpackages.com/badges/demos-europe-edt-queries/health.svg)](https://phpackages.com/packages/demos-europe-edt-queries)
```

###  Alternatives

[phpdocumentor/reflection-docblock

With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.

9.4k722.2M1.2k](/packages/phpdocumentor-reflection-docblock)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.4k5.6M651](/packages/sylius-sylius)[infection/infection

Infection is a Mutation Testing framework for PHP. The mutation adequacy score can be used to measure the effectiveness of a test set in terms of its ability to detect faults.

2.2k26.2M1.8k](/packages/infection-infection)[mailgun/mailgun-php

The Mailgun SDK provides methods for all API functions.

1.1k28.9M168](/packages/mailgun-mailgun-php)[driftingly/rector-laravel

Rector upgrades rules for Laravel Framework

1.2k12.0M462](/packages/driftingly-rector-laravel)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M152](/packages/sulu-sulu)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
