PHPackages                             kobykorman/eloquentify - 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. kobykorman/eloquentify

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

kobykorman/eloquentify
======================

Easily transform complex custom query results into fully hydrated hierarchical Eloquent models.

v2.1.0(2mo ago)201.0kMITPHPPHP ^8.2CI passing

Since Jul 4Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/kobykorman/eloquentify)[ Packagist](https://packagist.org/packages/kobykorman/eloquentify)[ Docs](https://github.com/kobykorman/eloquentify)[ RSS](/packages/kobykorman-eloquentify/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (5)Dependencies (8)Versions (7)Used By (0)

 [![Eloquentify Logo](./assets/logo.png)](./assets/logo.png)

Eloquentify for Laravel
-----------------------

[](#eloquentify-for-laravel)

👎 Lazy Loading (N+1 queries)

😑 Eager Loading (R+1 queries)

😎 Greedy Loading (1 query)

Why Eloquentify?
----------------

[](#why-eloquentify)

### ⚡ Single Query: N+1/R+1 round trips to the DB become one

[](#-single-query-n1r1-round-trips-to-the-db-become-one)

### 💯 Eloquent API: custom SQL in, fully hydrated Eloquent models out

[](#-eloquent-api-custom-sql-in-fully-hydrated-eloquent-models-out)

### ✨ Zero Config: your existing relation methods are all the wiring

[](#-zero-config-your-existing-relation-methods-are-all-the-wiring)

Using Eloquent can be costly in terms of how many queries are fired behind the scenes when a model has many relationships. What if we could leverage the database for what it was meant for while retaining the Eloquent experience?

Eloquentify easily transforms the result of a single custom query into nested Eloquent models, so you can continue enjoying the Eloquent API and all of its benefits. And since every one of those replaced queries was a sequential round trip to your database, collapsing them into one is a difference you can see.

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

[](#installation)

```
composer require kobykorman/eloquentify
```

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

[](#quick-start)

### 1. Add the trait:

[](#1-add-the-trait)

```
use Illuminate\Database\Eloquent\Model as BaseModel;
use KobyKorman\Eloquentify\EloquentifiesQueries;

class Model extends BaseModel
{
    use EloquentifiesQueries;
}
```

### 2. Write one query, aggregating each relation into a JSON column named after its relation method:

[](#2-write-one-query-aggregating-each-relation-into-a-json-column-named-after-its-relation-method)

```
// PostgreSQL
$result = DB::select("
    SELECT users.id, users.name, users.email,

        (SELECT json_build_object('id', profiles.id, 'bio', profiles.bio)
         FROM profiles WHERE profiles.user_id = users.id) AS profile,

        (SELECT json_agg(json_build_object(
            'id', roles.id, 'name', roles.name,

            'permissions', (SELECT json_agg(json_build_object('id', permissions.id, 'name', permissions.name))
                            FROM permissions
                            JOIN permission_role ON permission_role.permission_id = permissions.id
                            WHERE permission_role.role_id = roles.id)
        ))
        FROM roles
        JOIN role_user ON role_user.role_id = roles.id
        WHERE role_user.user_id = users.id) AS roles

    FROM users
    WHERE users.id = ?
", [$id]);
```

### 3. Hydrate:

[](#3-hydrate)

```
$user = User::eloquentify($result)->first();
```

### 4. Enjoy real Eloquent models:

[](#4-enjoy-real-eloquent-models)

```
$user->profile->bio;                          // hydrated HasOne
$user->roles->first()->permissions;           // nested collections, any depth
$user->roles->first()->name = 'Admin';
$user->roles->first()->save();                // they are real models
```

How it works
------------

[](#how-it-works)

For each column in your result, Eloquentify checks whether the model has a relation method with the same name (it must declare a relation return type, e.g. `: HasMany`). If it does, the column is decoded as JSON and hydrated recursively: a JSON object for to-one relations, a JSON array for to-many. Every other column becomes a plain attribute. That's the whole contract: **column alias = relation method name**.

Mistakes fail fast: invalid JSON, shape mismatches (an array where a to-one belongs), and ambiguous columns throw clear exceptions instead of guessing. Empty relations behave as you'd expect: `NULL` hydrates a to-one relation as `null` and a to-many as an empty collection, including the `[null]` arrays that aggregating over a left join produces.

### Pivot data (BelongsToMany)

[](#pivot-data-belongstomany)

Include a `pivot` key (or your custom `->as()` accessor name) inside each related object and it hydrates into the real pivot model, custom pivot classes included:

```
json_build_object('id', tags.id, 'name', tags.name,
                  'pivot', json_build_object('created_at', post_tag.created_at))
```

```
$post->tags->first()->pivot->created_at; // works exactly like native eager loading
```

### JSON functions per database

[](#json-functions-per-database)

to-many (JSON array)to-one (JSON object)PostgreSQL 9.4+`json_agg(...)``json_build_object(...)`MySQL 5.7.22+`JSON_ARRAYAGG(...)``JSON_OBJECT(...)`SQLite 3.38+ (or 3.9+ compiled with JSON1)`json_group_array(...)``json_object(...)`Requirements
------------

[](#requirements)

- PHP 8.2+, Laravel 11+
- A database with JSON aggregation: PostgreSQL 9.4+, MySQL 5.7.22+, or SQLite 3.38+ (see table above)
- Relation methods must declare relation return types (e.g. `: HasMany`), standard modern Laravel style
- One result row per root model, which is what JSON aggregation naturally produces

Limitations
-----------

[](#limitations)

- Relation method names are reserved: a scalar column aliased like a relation (`AS posts`) throws, so alias it differently (`AS posts_count`)
- `morphTo` relations can't be hydrated (the related class varies per row)
- Relation classes from third-party packages (e.g. belongs-to-through) are assumed to-many unless they extend Eloquent's to-one relations; a mismatch throws rather than misclassifies silently
- Binary columns can't ride JSON: encode them (e.g. base64) and cast back
- For high-precision decimals, emit text (`amount::text`) to avoid float precision loss in JSON
- Database JSON encoders reformat temporal values (PostgreSQL: ISO 8601 `2026-06-12T10:00:00`; MySQL: microseconds appended). Date casts parse these identically to native loading; only an uncast date column read as a raw string sees the format difference

New in v2 (for v1 users)
------------------------

[](#new-in-v2-for-v1-users)

v2 replaced v1's column prefixes with JSON aggregation (`json_agg` &amp; friends). In one move:

- No row multiplication: sibling "many" relations of any size are fine
- No prefixes: no collisions, no aliasing rules, no naming conventions
- Use any method name for the relation: alias the column after the method, including two relations to the same model and self-references
- Pivot data hydrates into real `->pivot` models
- Silent failures became exceptions

License
-------

[](#license)

This library is open-sourced software licensed under the [MIT license](LICENSE.md).

###  Health Score

47

—

FairBetter than 93% of packages

Maintenance87

Actively maintained with recent releases

Popularity28

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity54

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 ~68 days

Recently: every ~0 days

Total

6

Last Release

66d ago

Major Versions

v1.0.2 → v2.x-dev2026-06-12

PHP version history (2 changes)v1.0.0PHP &gt;=8.0

v2.x-devPHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/8a204a46e6816a6ffae3acb4e9a82fc07c72064e4772eadcde8569824dc65e09?d=identicon)[kobykorman](/maintainers/kobykorman)

---

Top Contributors

[![kobykorman](https://avatars.githubusercontent.com/u/5124919?v=4)](https://github.com/kobykorman "kobykorman (15 commits)")

---

Tags

laraveldatabaseperformanceormeloquentoptimization

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/kobykorman-eloquentify/health.svg)

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

###  Alternatives

[anourvalar/eloquent-serialize

Laravel Query Builder (Eloquent) serialization

11225.5M36](/packages/anourvalar-eloquent-serialize)[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)[sarfraznawaz2005/indexer

Laravel package to monitor SELECT queries and offer best possible INDEX fields.

562.7k](/packages/sarfraznawaz2005-indexer)[waad/laravel-model-metadata

A robust Laravel package for handling metadata with JSON casting, custom relation names, and advanced querying capabilities.

865.3k](/packages/waad-laravel-model-metadata)[ramadan/easy-model

A Laravel package for enjoyably managing database queries.

111.6k](/packages/ramadan-easy-model)

PHPackages © 2026

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