PHPackages                             alexandre-daubois/poq - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. alexandre-daubois/poq

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

alexandre-daubois/poq
=====================

Provides an object-oriented API to query in-memory collections in a SQL-style.

1.0.0-beta2(3y ago)1651MITPHPPHP &gt;=8.1

Since Jul 3Pushed 3y ago2 watchersCompare

[ Source](https://github.com/alexandre-daubois/poq)[ Packagist](https://packagist.org/packages/alexandre-daubois/poq)[ RSS](/packages/alexandre-daubois-poq/feed)WikiDiscussions main Synced 3d ago

READMEChangelog (2)Dependencies (1)Versions (4)Used By (0)

POQ - PHP Object Query
======================

[](#poq---php-object-query)

[![Minimum PHP Version](https://camo.githubusercontent.com/2d18ce514c7016022dad012ac9e39a8b6f47cc411b2daff6627cbf208f8cea63/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344253230382e312d3838393242462e7376673f7374796c653d666c61742d737175617265)](https://php.net/)[![CI](https://github.com/alexandre-daubois/poq/actions/workflows/php.yml/badge.svg)](https://github.com/alexandre-daubois/poq/actions/workflows/php.yml/badge.svg)[![Latest Unstable Version](https://camo.githubusercontent.com/0d4328a11413992aee7ef0c537cfff07496ba5013b0128c2fbb07365e285bbba/687474703a2f2f706f7365722e707567782e6f72672f616c6578616e6472652d646175626f69732f706f712f762f756e737461626c65)](https://packagist.org/packages/alexandre-daubois/poq)[![License](https://camo.githubusercontent.com/025c3c80411419a104a16e87a4c17a29aeb135cddfdc30e8b36fff4b3a943419/687474703a2f2f706f7365722e707567782e6f72672f616c6578616e6472652d646175626f69732f706f712f6c6963656e7365)](https://packagist.org/packages/alexandre-daubois/poq)

Install
-------

[](#install)

```
composer require alexandre-daubois/poq 1.0.0-beta2
```

That's it, ready to go! 🎉

Usage
-----

[](#usage)

Here is the set of data we're going to use in the follow examples:

```
$cities = [
    new City('Lyon', [
        new Person([
            new Child('Hubert', age: 30),
            new Child('Aleksandr', age: 18),
            new Child('Alexandre', age: 26),
            new Child('Alex', age: 25),
        ], height: 181),
        new Person([
            new Child('Fabien', age: 23),
            new Child('Nicolas', age: 8),
        ], height: 176),
        new Person([
            new Child('Alexis', age: 33),
            new Child('Pierre', age: 5),
        ], height: 185)
    ], minimalAge: 21),
    new City('Paris', [
        new Person([
            new Child('Will', age: 33),
            new Child('Alix', age: 32),
            new Child('Alan', age: 45),
        ], height: 185)
    ], minimalAge: 45)
];
```

The ObjectQuery object
----------------------

[](#the-objectquery-object)

The `ObjectQuery` object allows you to easily fetch deep information in your collections with ease. Just like Doctrine's `QueryBuilder`, plenty of utils methods are present for easy manipulation.

Moreover, you're able to create your query step-by-step and conditionally if needed. To create a simple query, all you need to do is call `ObjectQuery`'s `from` factory, and pass your collection as its source:

```
use ObjectQuery\ObjectQuery;

$query = ObjectQuery::from($this->cities, 'city');
```

From here, you're able to manipulate your collections and fetch data. First, let's see how to filter your collections. Note that the `city` argument is optional and defines an alias for the current collection. By default, the alias is `_`. Each alias must be unique in the query, meaning it is mandatory you pass an alias if you are dealing with deep collections. Defining an alias allows you to reference to the object later in the query. See the `selectMany` operation explanation for more details.

Modifiers (filtering, ordering, limiting, etc.)
-----------------------------------------------

[](#modifiers-filtering-ordering-limiting-etc)

Modifiers allow to filter results, order them, limit them and so on.

> 🔀 Modifiers can be given to the query in any order, as they are only applied when an operation is called.

### Where

[](#where)

#### Usage

[](#usage-1)

`where`, which takes a callback as an argument. This callback must return a boolean value.

```
use ObjectQuery\ObjectQuery;

$query = (ObjectQuery::from($this->cities, 'city'))
    ->where(
        function(City $city) {
            return \str_contains($city->name, 'Lyon') || \in_array($city->name, ['Paris', 'Rouen']);
        }
    );
```

### Order by

[](#order-by)

`orderBy`, which will order the collection. If the collection only contains scalar values, then you only have to pass an order. If your collection contains objects, you have to pass the order as well as the field to order on. Available orders are: `QueryOrder::Ascending`, `QueryOrder::Descending`, `QueryOrder::None` and `QueryOrder::Shuffle`.

```
use ObjectQuery\ObjectQuery;
use ObjectQuery\ObjectQueryOrder;

$query = (ObjectQuery::from($this->cities))
    ->orderBy(ObjectQueryOrder::Ascending, 'name');
```

### Offset

[](#offset)

`offset` modifier changes the position of the first element that will be retrieved from the collection. This is particularly useful when doing pagination, in conjunction with the `limit` modifier. The offset must be a positive integer, or `null` to remove any offset.

```
use ObjectQuery\ObjectQuery;

$query = ObjectQuery::from($this->cities);

// Skip the 2 first cities of the collection and fetch the rest
$query->offset(2)
    ->select();

// Unset any offset, no data will be skipped
$query->offset(null)
    ->select();
```

### Limit

[](#limit)

The `limit` modifier limit the number of results that will be used by different operations, such as `select`. The limit must be a positive integer, or `null` to remove any limit.

```
use ObjectQuery\ObjectQuery;

$query = ObjectQuery::from($this->cities);

// Only the first 2 results will be fetched by the `select` operation
$query->limit(2)
    ->select();

// Unset any limitation, all matching results will be used in the `select` operations
$query->limit(null)
    ->select();
```

Operations
----------

[](#operations)

Operations allow you to fetch filtered data in a certain format. Here is a list of the available operations and how to use them.

### Select

[](#select)

This is the most basic operation. It returns filtered data of the query. It is possible to pass the exact field we want to retrieve, as well as multiple fields. If no argument is passed to `select`, it will retrieve the whole object. You must not pass any argument when dealing with scalar collections.

```
use ObjectQuery\ObjectQuery;

$query = ObjectQuery::from($this->cities);

// Retrieve the whole object
$query->select();

// Retrieve one field
$query->select('name');

// Retrieve multiple fields
$query->select(['name', 'minimalAge']);
```

### Select One

[](#select-one)

When querying a collection, and we know in advance that only one result is going to match, this could be redundant to use `select` and retrieve result array's first element everytime. `selectOne` is designed exactly for this case. The behavior of this operation is the following:

- If a single result is found, it will be returned directly without enclosing it in an array of 1 element.
- If no result is found, the `selectOne` operation returns `null`.
- If more than on result is found, then a `NonUniqueResultException` is thrown.

```
use ObjectQuery\Exception\NonUniqueResultException;

$query = (ObjectQuery::from($this->cities, 'city'))
    ->where(fn($city) => $city->name === 'Lyon');

try {
    $city = $query->selectOne(); // $city is an instance of City

    // You can also query a precise field
    $cityName = $query->selectOne('name'); // $cityName is a string
} catch (NonUniqueResultException) {
    // ...
}
```

### Select Many

[](#select-many)

This operation allows you to go deeper in a collection. Let's say your collection contains many objects with collections inside them, this is what you're going to use to fetch and filter collections.

Note that we defined an alias for city, **which allows to reference the parent city in the last `where` call**.

```
use ObjectQuery\ObjectQuery;
use ObjectQuery\ObjectQueryContextEnvironment;

$query = (ObjectQuery::from($this->cities, 'city'))
    ->where(fn($city) => \in_array($city->name, ['Paris', 'Rouen']))
    ->selectMany('persons', 'person')
        ->where(fn($person) => $person->height >= 180)
        ->selectMany('children', 'child')
            ->where(fn($child, ObjectQueryContextEnvironment $context) => \str_starts_with($child->name, 'Al') && $child->age >= $context->get('city')->minimalAge);
```

Like `from`, `selectMany` also takes an alias as an argument. This way, you will be able to reference ancestors in your `where` calls, as shown in the above example.

### Count

[](#count)

This operation returns the size of the current filtered collection:

```
$query = ObjectQuery::from($this->cities);

$query->count();
```

### Concat

[](#concat)

This operation will concatenate the collection with a given separator. If you're dealing with a scalar collection, there is no mandatory argument. If dealing with collections of objects, the `field` argument must be passed.

```
$query = ObjectQuery::from($this->cities);

$query->concat(', ', 'name');
```

### Each

[](#each)

This operation allows you to pass a callback, which will be applied to each element of the filtered collection. You can see this as a `foreach`.

```
$query = ObjectQuery::from($this->cities);

// Append an exclamation point to every city name
$query->each(fn($element) => $element->name.' !');
```

### Min and Max

[](#min-and-max)

These operations will return the maximum and the minimum of the collection. You can use this on scalar collections. Internally, these operations use `min()` and `max()` functions of the Standard PHP Library, so the same rules apply.

```
use ObjectQuery\ObjectQuery;

$query = (ObjectQuery::from($this->cities))
        ->selectMany('persons', 'person')
            ->selectMany('children', 'child');

$query->min('age'); // 5
$query->max('age'); // 45
$query->min('name'); // "Alan"
$query->max('name'); // "Will"
```

### Sum

[](#sum)

`sum` returns the sum of a collection. If the collection contains objects, a field must be provided in order to calculate the sum of it. This only works with collections of numerics, and an exception is thrown if any item of the collection returns `false` to the `\is_numeric()` function.

```
use ObjectQuery\ObjectQuery;

$query = (ObjectQuery::from($this->cities))
        ->selectMany('persons', 'person')
            ->selectMany('children', 'child');

$query->sum('age');
```

### Average

[](#average)

`average` returns the average of a collection. If the collection contains objects, a field must be provided in order to calculate the average of it. This only works with collections of numerics, and an exception is thrown if any item of the collection returns `false` to the `\is_numeric()` function.

```
use ObjectQuery\ObjectQuery;

$query = (ObjectQuery::from($this->cities))
        ->selectMany('persons', 'person')
            ->selectMany('children', 'child');

$query->average('age');
```

###  Health Score

23

—

LowBetter than 27% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity12

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~0 days

Total

2

Last Release

1408d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/4df244f8a69ff326bf04b0eafa163051f41826db1ffeb8ffa6b5b7fc425e6b9e?d=identicon)[alexandre-daubois](/maintainers/alexandre-daubois)

---

Top Contributors

[![alexandre-daubois](https://avatars.githubusercontent.com/u/2144837?v=4)](https://github.com/alexandre-daubois "alexandre-daubois (7 commits)")

---

Tags

linqobjectphpqueryobjectquerycollectionlinq

### Embed Badge

![Health badge](/badges/alexandre-daubois-poq/health.svg)

```
[![Health](https://phpackages.com/badges/alexandre-daubois-poq/health.svg)](https://phpackages.com/packages/alexandre-daubois-poq)
```

###  Alternatives

[myclabs/deep-copy

Create deep copies (clones) of your objects

8.9k849.8M169](/packages/myclabs-deep-copy)[symfony/property-access

Provides functions to read and write from/to an object or array using a simple string notation

2.8k295.3M2.5k](/packages/symfony-property-access)[athari/yalinqo

YaLinqo, a LINQ-to-objects library for PHP

4561.2M5](/packages/athari-yalinqo)[league/uri-components

URI components manipulation library

31932.3M67](/packages/league-uri-components)[ginq/ginq

LINQ to Object inspired DSL for PHP

192257.5k3](/packages/ginq-ginq)[jasny/dotkey

Dot notation access for objects and arrays

14219.5k6](/packages/jasny-dotkey)

PHPackages © 2026

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