Over the years of being a developer I've been fortunate enough to get to use a number of different frameworks to build applications with.
I remember when I first started to use CakePHP and it baffled me that there were two separate files for the same database table you had a Table class and a Entity class for instance PostsTable and Post entity. After A while of using the framework it made sense to me.
The table handles database behaviour - querying, associations, persistence. The entity handles your data - its shape, its rules, its logic as a PHP object. They're different responsibilities, even when they touch the same table.
Since moving to Laravel I've thought about this separation a lot. Eloquent is brilliant - I'm not changing my view on that. But passing models through every layer of an application creates problems that compound:
→ Any layer can call save() by accident
→ No real type safety - magic __get() all the way down
→ Services become Eloquent-coupled and painful to unit test
→ Database column names leak into your domain logic
At
@jumptwenty4 we've used DTOs for the input side for years packages like
@spatie_be Laravel Data really helped with this.
A recently released package by
@wendell_adriel called Laravel Expressive landed this week. It instantly reminded me of the CakePHP Entity pattern but done for Laravel
One trait on your model. One Artisan command. Your services and actions receive typed PHP objects - public, typed properties, proper enums, no Eloquent magic.
The bit that surprised me: what it does for testing. Once your services accept Expressive objects, unit tests mean constructing a plain PHP object. No database. No factories. No mocking Eloquent.
I've written a breakdown on the Jump24 journal - code examples, Pest testing patterns and an honest look at every limitation worth knowing before you adopt:
jump24.co.uk/journal/laravel…
Big thanks to Wendell Adriel once again for all the work he's put in for this new package.