Installation
composer require oobook/snapshot
Publish Migrations & Config
php artisan vendor:publish --tag="snapshot-migrations"
php artisan vendor:publish --tag="snapshot-config"
Run migrations:
php artisan migrate
Apply Trait to Model
Add HasSnapshot trait to your Eloquent model:
use Oobook\Snapshot\Concerns\HasSnapshot;
class Product extends Model
{
use HasSnapshot;
}
// Create a snapshot of an existing model
$product = Product::find(1);
$snapshot = $product->snapshot();
// Force sync relationships (optional)
$snapshot->syncSnapshot();
$snapshot = $model->snapshot();
config/snapshot.php:
'table' => 'custom_snapshots',
Then use:
$snapshot = $model->snapshot(['table' => 'custom_snapshots']);
'sync_relationships' => true,
$snapshot->syncSnapshot();
$snapshots = Product::find(1)->snapshots();
$snapshots = Product::find(1)->snapshots()->where('created_at', '>', now()->subDays(7));
$snapshot->restore();
$snapshot->forceRestore();
If your model uses SoftDeletes, ensure the snapshot table includes deleted_at:
use Illuminate\Database\Eloquent\SoftDeletes;
class Product extends Model
{
use HasSnapshot, SoftDeletes;
}
Trigger snapshots on model events (e.g., updating):
class ProductObserver
{
public function updating(Product $product)
{
$product->snapshot();
}
}
Example Laravel route:
Route::post('/products/{id}/snapshot', function (Product $product) {
return $product->snapshot();
});
Use snapshots in tests to isolate data:
public function test_snapshot_creation()
{
$product = Product::factory()->create();
$snapshot = $product->snapshot();
$this->assertDatabaseHas('snapshots', [
'snapshotable_id' => $product->id,
'snapshotable_type' => Product::class,
]);
}
HasSnapshot or manually sync:
$snapshot->syncSnapshot(['with' => ['category', 'tags']]);
guarded is not set.$guarded in your model:
protected $guarded = ['password', 'api_token'];
'sync_relationships' => false,
created_at/updated_at are manually set, snapshots may behave unexpectedly.useTimestamps = false in the snapshot model or override:
public function getSnapshotModel()
{
return \Oobook\Snapshot\Models\Snapshot::class;
}
Verify data exists:
\DB::table('snapshots')->where('snapshotable_id', $model->id)->get();
Enable debug mode in config:
'debug' => true,
Check Laravel logs for sync errors.
Ensure polymorphic relationships are correctly defined:
public function snapshots()
{
return $this->morphMany(\Oobook\Snapshot\Models\Snapshot::class, 'snapshotable');
}
Extend the default snapshot model:
namespace App\Models;
use Oobook\Snapshot\Models\Snapshot as BaseSnapshot;
class Snapshot extends BaseSnapshot
{
protected $casts = [
'metadata' => 'array',
];
}
Override in your model:
public function getSnapshotModel()
{
return \App\Models\Snapshot::class;
}
Attach metadata to snapshots:
$snapshot = $model->snapshot(['metadata' => ['user_id' => auth()->id()]]);
Use model events:
class Product extends Model
{
use HasSnapshot;
protected static function booted()
{
static::creating(function ($model) {
// Pre-snapshot logic
});
static::created(function ($model) {
// Post-snapshot logic
});
}
}
Create snapshots for a collection:
$products = Product::all();
$snapshots = collect($products)->map->snapshot();
How can I help you explore Laravel packages today?