raveren / eloquent-data-object
Store strictly typed PHP objects in Eloquent JSON columns. Data class changes never invalidate stored data.
v1.0.1
2026-05-21 09:07 UTC
Requires
- netresearch/jsonmapper: ^4.0 || ^5.0
Requires (Dev)
- illuminate/contracts: ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0
- illuminate/database: ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0
- pestphp/pest: ^4.0
This package is auto-updated.
Last update: 2026-05-21 09:08:58 UTC
README
Store strictly typed PHP objects in Eloquent JSON columns. Data class changes never invalidate stored data.
Installation
composer require raveren/eloquent-data-object
What this does
Your model column becomes a strictly typed object!
Any changes to your data classes in the future don't invalidate stored data!
How it works
Just extend EloquentDataObject (or see below if you can't):
<?php use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; use Raveren\EloquentDataObject\EloquentDataObject; class MyData extends EloquentDataObject ##### <---- Step 1/3: extend EloquentDataObject ###### { public string $name; /** @var MyData[] */ public array $children; } class MyModel extends Model { protected function casts(): array { return [ 'json_data' => MyData::class ##### <---- Step 2/3: add Eloquent cast ###### ]; } } Schema::table('my_table', function (Blueprint $table) { $table->json('json_data')->nullable(); ##### <---- Step 3/3: create DB column ###### });
🎉 Done!
Objects are stored as JSON inside the database.
In PHP $myModel->json_data is always an instance of MyData.
Thus, if you receive an associative-array representation, you must convert it to MyData before saving:
$myModel->json_data = MyData::from($array); // helper method comes in the box
If your data class changes
- No data is ever lost, and you get no errors (see 5. below).
- If you rename or remove a class attribute, existing data will be preserved as a Dynamic property with the old name on the class instance (no data loss).
- To fix drifted names inside the database, define a
renamedDataObjectColumns():
class MyData extends EloquentDataObject { public string $newName; public static function renamedDataObjectColumns(): array // <----- This { return [ 'name' => 'newName', 'children' => null, // Set new name to null to drop the value from storage on saving. ]; } }
- It's enough to load each model once and save it to fix the data inside the DB permanently, so you don't have to keep the
renamedDataObjectColumns()method if you do that. - Attributes that appear in database JSON, but are missing in class definitions issue
Log::error()with detailed information. You can provide your own error handler instead, example:
// app/Providers/AppServiceProvider.php EloquentDataObject::setMissingAttributeHandler( static fn(string $targetClassname, string $currentClassname, string $missingKey) => report( new Exception( sprintf( 'EloquentDataObject cast for %s has unrecognized property %s->%s. To solve, extend `renamedDataObjectColumns(): array` in your data class.', $targetClassname, $targetObject::class, $key, ), ), ); );
If you cannot extend a class :
- Add
use EloquentDataObjectTrait; - Add
implements Castable - Annotate with
#[AllowDynamicProperties](only if you renamed class attributes)
#[AllowDynamicProperties] class MyData implements Castable { use EloquentDataObjectTrait; // ... }
Acknowledgments
Hierarchical object conversion is handled by netresearch/jsonmapper (sole project dependency).
Licence
Unlicence, do whatever you want with it.
