PHPackages                             salvatorecervone/memoryquerybuilder - 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. [Database &amp; ORM](/categories/database)
4. /
5. salvatorecervone/memoryquerybuilder

ActiveLibrary[Database &amp; ORM](/categories/database)

salvatorecervone/memoryquerybuilder
===================================

An Eloquent-style in-memory query builder for PHP arrays and objects

v1.0.1(yesterday)10MITPHPPHP &gt;=8.1

Since Aug 16Pushed today1 watchersCompare

[ Source](https://github.com/SalvatoreCervone/memoryquerybuilder)[ Packagist](https://packagist.org/packages/salvatorecervone/memoryquerybuilder)[ Docs](https://github.com/SalvatoreCervone/memoryquerybuilder)[ RSS](/packages/salvatorecervone-memoryquerybuilder/feed)WikiDiscussions master Synced today

READMEChangelogDependencies (1)Versions (3)Used By (0)

MemoryQueryBuilder
==================

[](#memoryquerybuilder)

> **Eloquent-style in-memory query builder for PHP 8.1+**Filter, sort, aggregate and paginate any array or object collection with a fluent, chainable API — no database required.

[![PHP](https://camo.githubusercontent.com/bb4c144f032fe46e1296df97f21f87c666485f2d47b80efc47ecd5c22251237c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e312532422d626c75653f6c6f676f3d706870)](https://www.php.net/)[![License](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](LICENSE)[![Tests](https://camo.githubusercontent.com/6fe3da33039e0b59f1293cd4838fd0de80c64f372c640eda187000ab66623da7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d3133322532307061737365642d627269676874677265656e)](#running-tests)

```
$result = MemoryQueryBuilder::from($myArray)
    ->where('status', 'active')
    ->where('age', '>=', 18)
    ->orderByDesc('created_at')
    ->limit(10)
    ->get();
```

---

Table of Contents
-----------------

[](#table-of-contents)

- [Installation](#installation)
- [Quick Start](#quick-start)
- [Data Sources](#data-sources)
- [WHERE Clauses](#where-clauses)
- [Ordering](#ordering)
- [Select &amp; Distinct](#select--distinct)
- [Limit, Offset &amp; Pagination](#limit-offset--pagination)
- [Group By &amp; Having](#group-by--having)
- [Aggregations](#aggregations)
- [Execution Methods](#execution-methods)
- [Collection API](#collection-api)
- [Running Tests](#running-tests)

---

Installation
------------

[](#installation)

```
composer require salvatorecervone/memoryquerybuilder
```

Or clone directly:

```
git clone https://github.com/SalvatoreCervone/memoryquerybuilder.git
cd memoryquerybuilder
composer install
```

---

Quick Start
-----------

[](#quick-start)

```
use MemoryQueryBuilder\MemoryQueryBuilder;

$users = [
    ['id' => 1, 'name' => 'Alice', 'age' => 30, 'role' => 'admin',  'status' => 'active'],
    ['id' => 2, 'name' => 'Bob',   'age' => 17, 'role' => 'user',   'status' => 'inactive'],
    ['id' => 3, 'name' => 'Carol', 'age' => 25, 'role' => 'editor', 'status' => 'active'],
];

// Filter + order
$result = MemoryQueryBuilder::from($users)
    ->where('status', 'active')
    ->where('age', '>=', 18)
    ->orderBy('name')
    ->get(); // returns a Collection

// Aggregations
echo MemoryQueryBuilder::from($users)->avg('age');  // 24.0
echo MemoryQueryBuilder::from($users)->count();     // 3

// Pagination
$page = MemoryQueryBuilder::from($users)->paginate(perPage: 2, page: 1);
echo $page->total();     // 3
echo $page->lastPage();  // 2
```

---

Data Sources
------------

[](#data-sources)

MemoryQueryBuilder works with **any iterable data source**:

```
// Plain associative arrays
MemoryQueryBuilder::from([['id' => 1, 'name' => 'Alice'], ...]);

// stdClass objects
$obj = new stdClass();
$obj->id = 1; $obj->name = 'Alice';
MemoryQueryBuilder::from([$obj]);

// Objects with getter methods (private/protected properties)
// 'name' resolves to getName(), 'is_active' resolves to isIsActive()
class User {
    public function __construct(private string $name, private bool $isActive) {}
    public function getName(): string { return $this->name; }
    public function isIsActive(): bool { return $this->isActive; }
}
MemoryQueryBuilder::from([$user1, $user2]);

// Generators / Traversable
$generator = (function() {
    yield ['id' => 1, 'val' => 10];
    yield ['id' => 2, 'val' => 20];
})();
MemoryQueryBuilder::from($generator);

// Mixed arrays + objects in the same dataset ✓
MemoryQueryBuilder::from([$array, $stdClass, $entity]);
```

### Dot-Notation for Nested Data

[](#dot-notation-for-nested-data)

Access nested fields at any depth using `.` notation:

```
$data = [
    ['user' => ['name' => 'Alice', 'address' => ['city' => 'Rome']]],
    ['user' => ['name' => 'Bob',   'address' => ['city' => 'Milan']]],
];

MemoryQueryBuilder::from($data)
    ->where('user.address.city', 'Rome')
    ->pluck('user.name')
    ->select('user.name as author', 'user.address.city as city')
    ->get();
```

---

WHERE Clauses
-------------

[](#where-clauses)

### Basic

[](#basic)

```
->where('column', 'value')             // operator defaults to '='
->where('column', '>=', 100)
->orWhere('role', 'admin')
->orWhere('score', '>', 90)
```

### Operators Supported

[](#operators-supported)

OperatorDescription`=`, `==`, `===`Equality`!=`, ``, `!==`Inequality`=`Comparisons`like`, `not like`SQL-style pattern (`%`, `_`), case-sensitive`ilike`, `not ilike`Case-insensitive LIKE`contains`, `icontains`Substring match`starts_with`, `ends_with`Prefix / suffix match`in`, `not in`Value in array`between`, `not between`Range check `[min, max]``regexp`, `not regexp`Regular expression```
->where('name', 'like', 'A%')
->where('email', 'regexp', '^[a-z]+@example\.com$')
->where('role', 'in', ['admin', 'editor'])
->where('age', 'between', [18, 65])
```

### Dedicated Helpers

[](#dedicated-helpers)

```
->whereIn('role', ['admin', 'editor'])
->whereNotIn('status', ['cancelled', 'refunded'])
->orWhereIn('tag', ['featured'])
->orWhereNotIn('status', ['archived'])

->whereNull('deleted_at')
->whereNotNull('email')
->orWhereNull('verified_at')

->whereBetween('age', [18, 65])
->whereNotBetween('score', [0, 50])
->orWhereBetween('created_at', ['2024-01-01', '2024-12-31'])

->whereLike('email', '%@example.com')         // case-insensitive by default
->whereLike('name', 'Alice', caseSensitive: true)
->whereNotLike('email', '%@spam.com')

->whereContains('bio', 'developer')           // case-insensitive by default
->whereStartsWith('name', 'Al')
->whereEndsWith('email', '.org')

->whereYear('created_at', '=', 2024)
->whereMonth('created_at', '>=', 6)
->whereDay('created_at', '=', 90);
    })
    ->get();
```

### Conditional Queries

[](#conditional-queries)

```
$search   = 'alice';  // or null to skip
$minScore = 50;

MemoryQueryBuilder::from($users)
    ->when($search,   fn($q, $v) => $q->whereLike('name', "%{$v}%"))
    ->when($minScore, fn($q, $v) => $q->where('score', '>=', $v))
    ->unless($isAdmin, fn($q)   => $q->where('public', true))
    ->get();
```

---

Ordering
--------

[](#ordering)

```
->orderBy('name')                    // ASC (default)
->orderBy('name', 'desc')
->orderByDesc('created_at')

// Multi-column ordering
->orderBy('department')->orderByDesc('salary')

// Random order
->inRandomOrder()
->inRandomOrder(seed: 42)            // reproducible random
```

---

Select &amp; Distinct
---------------------

[](#select--distinct)

```
// Select specific columns
->select('id', 'name', 'email')

// Dot-notation + aliasing
->select('id', 'user.name as author', 'user.address.city as city')

// Add to existing selection
->addSelect('extra_col')

// Remove duplicates
->distinct()                         // full-item deduplication
->distinct('category')               // deduplicate by specific column
```

---

Limit, Offset &amp; Pagination
------------------------------

[](#limit-offset--pagination)

```
->limit(10)   // or ->take(10)
->offset(20)  // or ->skip(20)
->forPage(page: 2, perPage: 10)

// Full pagination with metadata
$paginator = MemoryQueryBuilder::from($data)
    ->where('status', 'active')
    ->orderBy('name')
    ->paginate(perPage: 15, page: 1);

$paginator->total();          // total matching items
$paginator->perPage();        // items per page
$paginator->currentPage();    // current page number
$paginator->lastPage();       // number of last page
$paginator->from();           // first item index on this page (1-based)
$paginator->to();             // last item index on this page
$paginator->hasMorePages();   // bool
$paginator->items();          // array of items on this page
$paginator->toArray();        // ['total' => ..., 'per_page' => ..., 'data' => [...], ...]
json_encode($paginator);      // implements JsonSerializable
```

---

Group By &amp; Having
---------------------

[](#group-by--having)

```
$result = MemoryQueryBuilder::from($sales)
    ->groupBy('department')
    ->having('count', '>', 2)
    ->orHaving('department', 'Finance')
    ->get();

// Each group item includes:
// - the group-by column(s): $group['department']
// - '_group_key': composite key string
// - '_items': array of original items in the group
// - 'count': number of items in the group
foreach ($result as $group) {
    echo "{$group['department']}: {$group['count']} employees";
}
```

---

Aggregations
------------

[](#aggregations)

```
$q = MemoryQueryBuilder::from($orders)->where('status', 'paid');

$q->count();              // number of matching items
$q->count('column');      // count non-null values in column
$q->sum('amount');        // float
$q->avg('price');         // float (0 if empty)
$q->min('score');         // mixed (null if empty)
$q->max('score');         // mixed (null if empty)
```

---

Execution Methods
-----------------

[](#execution-methods)

```
->get(): Collection                   // all matching items
->first(): mixed                      // first match or null
->firstOrFail(): mixed                // first match or throws ItemNotFoundException
->last(): mixed                       // last match or null
->find(42): mixed                     // find by primary key (default: 'id')
->find(42, 'uuid'): mixed             // find by custom key
->findOrFail(42): mixed               // find or throws ItemNotFoundException
->value('column'): mixed              // value from first match
->pluck('name'): Collection           // list of values
->pluck('name', 'id'): Collection     // assoc: id => name
->exists(): bool
->doesntExist(): bool
->chunk(100, fn($chunk) => ...): bool // process in batches; return false to stop
->toArray(): array
->toJson(): string
```

---

Collection API
--------------

[](#collection-api)

`get()` returns a `Collection` object that implements `ArrayAccess`, `IteratorAggregate`, `Countable`, and `JsonSerializable`.

```
$col = MemoryQueryBuilder::from($data)->get();

// Transformation & Type Conversion
$col->map(fn($item) => $item['name']);
$col->filter(fn($item) => $item['active']);
$col->reduce(fn($carry, $item) => $carry + $item['score'], 0);
$col->each(fn($item) => processItem($item));  // return false to break
$col->transform(fn($item) => [...$item, 'extra' => true]);  // in-place
$col->toObjects();                           // convert array items to stdClass objects
$col->toObjects(recursive: true);            // deep convert nested arrays to objects
$col->toArrays();                            // convert objects to associative arrays
$col->toArrays(recursive: true);             // deep convert nested objects to arrays

// Sorting
$col->sortBy('name');
$col->sortByDesc('score');
$col->sortBy(fn($item) => strlen($item['name']));

// Grouping & Slicing
$col->groupBy('department');     // returns array
$col->unique('email');
$col->take(5);
$col->skip(10);
$col->slice(offset: 2, length: 5);

// Search
$col->first();
$col->first(fn($item) => $item['role'] === 'admin');
$col->last();
$col->contains(fn($item) => $item['id'] === 42);
$col->contains('Alice');                         // simple value search

// Pluck
$col->pluck('name');
$col->pluck('name', 'id');

// Aggregations
$col->sum('amount');
$col->avg('score');
$col->min('price');
$col->max('price');
$col->count();
$col->isEmpty();
$col->isNotEmpty();

// Serialization
$col->toArray();
$col->toJson();
(string) $col;           // same as toJson()
json_encode($col);       // implements JsonSerializable

// ArrayAccess
$col[0];
$col[] = $newItem;
unset($col[2]);
isset($col[0]);

// Iterable
foreach ($col as $item) { ... }
```

---

Running Tests
-------------

[](#running-tests)

```
git clone https://github.com/SalvatoreCervone/memoryquerybuilder.git
cd memoryquerybuilder
composer install
vendor/bin/phpunit --testdox
```

```
OK (132 tests, 218 assertions)

```

---

License
-------

[](#license)

MIT — feel free to use, modify, and distribute.

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance100

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity43

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

1d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/40053308?v=4)[SalvatoreCervone](/maintainers/SalvatoreCervone)[@SalvatoreCervone](https://github.com/SalvatoreCervone)

---

Top Contributors

[![SalvatoreCervone](https://avatars.githubusercontent.com/u/40053308?v=4)](https://github.com/SalvatoreCervone "SalvatoreCervone (5 commits)")

---

Tags

phplaraveleloquentcollectionquery builderlinqIn Memorydata filterjson-queryfluent queryarray-searcharray-filterarray-query-builderin-memory-query-builder

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/salvatorecervone-memoryquerybuilder/health.svg)

```
[![Health](https://phpackages.com/badges/salvatorecervone-memoryquerybuilder/health.svg)](https://phpackages.com/packages/salvatorecervone-memoryquerybuilder)
```

###  Alternatives

[matchory/elasticsearch

The missing elasticsearch ORM for Laravel!

3066.0k](/packages/matchory-elasticsearch)[wayofdev/laravel-cycle-orm-adapter

🔥 A Laravel adapter for CycleORM, providing seamless integration of the Cycle DataMapper ORM for advanced database handling and object mapping in PHP applications.

3542.5k3](/packages/wayofdev-laravel-cycle-orm-adapter)[salehhashemi/laravel-repository

Implementing the repository pattern for Laravel projects.

2010.7k](/packages/salehhashemi-laravel-repository)

PHPackages © 2026

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