Search by

sineld / simple-eloquent

Hydration-free Eloquent queries: retrieve results as plain objects with full relation support

Maintainers

Package info

github.com/sineld/simple-eloquent

pkg:composer/sineld/simple-eloquent

Transparency log

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

Stars: 0

v1.0.0 2026-09-01 19:18 UTC

README

tests Latest Version Total Downloads License

Hydration-free Eloquent queries. Add simple() to a query chain and results come back as plain stdClass objects instead of hydrated models — with full relation and pagination support. On read-heavy queries that is 4–12x faster with up to 2.5x less memory, measured, not estimated.

Fork notice. This is an actively maintained fork of volosyuk/simple-eloquent by Andrey Volosyuk, who designed and wrote the original package. The fork exists to ship support for new Laravel majors on release day (constraints already allow the next major, and CI tests weekly against the framework's master branch), along with modern tooling: PHPUnit 11, PHPStan, Pint, GitHub Actions.

When to use it

Eloquent hydration is pure overhead when a page only displays data: index tables, dashboards, exports, API listings. simple() skips model instantiation, casts, accessors and events, returning raw attributes with relations attached. Keep using plain Eloquent whenever you need mutators, casting, or to call methods on the model.

Real-world scenarios

Every listing screen in a typical app is a hydration hotspot. The same query, one simple() call apart:

The admin index table — 50 rows, a relation, pagination. The bread and butter of every back office:

// 0.7 ms → 0.2 ms, 4x faster
$articles = Article::with('category')->simple()->paginate(50);

The JSON API endpoint — a mobile app asks for 1,000 records; nobody will ever call save() on them:

// 8.3 ms → 0.9 ms, 9x faster, 2.5x less memory
return Article::with('category')->limit(1000)->simple()->get();

The CSV/Excel export — 10,000 rows streamed to a file. Hydrating models here buys you nothing but a memory spike:

// 82 ms → 8 ms, 10x faster, 15 MB → 6 MB
$rows = Article::with('category')->simple()->get();

The dashboard widget — categories with their articles via hasMany, rebuilt on every page view:

// 66 ms → 5 ms, 12x faster, half the memory
$feed = Category::with('articles')->simple()->get();

Measured on PHP 8.4 with an in-memory SQLite database (10,000 articles, 20 categories), median of 5 runs — so the numbers isolate exactly what this package removes: hydration cost. Your absolute totals will include real query time on top, but the saved milliseconds and megabytes come with you. Reproduce them yourself:

composer install && php benchmarks/bench.php

Requirements

  • PHP 8.2 – 8.5 (the upcoming PHP release is covered by a nightly CI job)
  • Laravel 12 or 13 (constraints already allow 14 — it installs the day it ships)

Installation

composer require sineld/simple-eloquent

Usage

Add the trait to your model. For eager-loaded relations, add it to the related models too:

use Volosyuk\SimpleEloquent\SimpleEloquent;

class Department extends Model
{
    use SimpleEloquent;
}

Then put simple() anywhere in the query chain:

$users = User::whereHas('units')
    ->with('units')
    ->withCount('units')
    ->limit(10)
    ->simple()
    ->get(); // Collection of stdClass, relations attached

$activeUser = User::simple()->where('is_active', 1)->first();

$page = Article::simple()->latest()->paginate(25);

After simple(), the familiar terminal methods return plain objects instead of models: get, first, firstOrFail, find, findOrFail, findMany, paginate, simplePaginate. The explicit variants (getSimple(), firstSimple(), findSimple(), paginateSimple(), allSimple(), …) also exist if you prefer not to toggle the builder.

Both PDO::FETCH_OBJ and PDO::FETCH_ASSOC fetch modes are supported — results follow your connection's fetch mode.

What you give up

Results are stdClass objects (or arrays), not models: no casts, no accessors or appends, no save()/update(), no model events. That is exactly where the speed comes from. Reach for it on read paths, not write paths.

Upgrading from volosyuk/simple-eloquent

The namespace is unchanged (Volosyuk\SimpleEloquent), so the swap is only a composer change — no code edits:

composer remove volosyuk/simple-eloquent
composer require sineld/simple-eloquent

Development

composer test    # PHPUnit
composer lint    # Pint (check)
composer stan    # PHPStan level 5
composer check   # all of the above

CI runs the suite on PHP 8.2–8.5 against every supported Laravel release, plus a weekly run against laravel/framework@master and PHP nightly to catch next-major breakage months before it lands.

Credits

License

MIT — see LICENSE.txt. Original copyright belongs to Andrey Volosyuk.