-
-
Notifications
You must be signed in to change notification settings - Fork 0
Examples
This page contains practical examples demonstrating various Laravel Snapshot features and use cases.
Simple snapshot creation and comparison:
use App\Models\User;
use Grazulex\LaravelSnapshot\Snapshot;
// Create a test user
$user = User::factory()->create([
'name' => 'John Doe',
'email' => 'john@example.com',
]);
// Create initial snapshot
Snapshot::save($user, 'user-initial');
// Modify the user
$user->update([
'name' => 'John Smith',
'email' => 'john.smith@example.com',
]);
// Create second snapshot
Snapshot::save($user, 'user-updated');
// Compare snapshots
$diff = Snapshot::diff('user-initial', 'user-updated');
// Display changes
foreach ($diff['modified'] as $field => $changes) {
echo "{$field}: '{$changes['from']}' β '{$changes['to']}'";
}
Using the convenient trait methods:
use Grazulex\LaravelSnapshot\Traits\HasSnapshots;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
use HasSnapshots;
protected $fillable = ['customer_name', 'total', 'status'];
}
// Create order with automatic snapshot
$order = Order::create([
'customer_name' => 'Jane Doe',
'total' => 99.99,
'status' => 'pending'
]);
// Create labeled snapshot
$order->snapshot('order-created');
// Get all snapshots for this order
$snapshots = $order->snapshots;
// Get timeline
$timeline = $order->getSnapshotTimeline();
// Generate HTML report
$report = $order->getHistoryReport('html');
Command-line examples:
# Create a snapshot
php artisan snapshot:save "App\Models\User" --id=1 --label=before-update
# List all snapshots
php artisan snapshot:list
# Compare two snapshots
php artisan snapshot:diff before-update after-update
# Generate a report
php artisan snapshot:report --model="App\Models\User" --id=1
Track order changes through processing pipeline:
use App\Models\Order;
use Grazulex\LaravelSnapshot\Snapshot;
class OrderProcessor
{
public function processOrder(Order $order)
{
// Snapshot before processing
Snapshot::save($order, "order-{$order->id}-processing-start");
// Apply discount
$order->update(['total' => $order->total * 0.9]);
Snapshot::save($order, "order-{$order->id}-discount-applied");
// Calculate tax
$order->update(['tax' => $order->total * 0.1]);
Snapshot::save($order, "order-{$order->id}-tax-calculated");
// Update status
$order->update(['status' => 'processed']);
Snapshot::save($order, "order-{$order->id}-processing-complete");
// Generate processing report
return $this->generateProcessingReport($order);
}
private function generateProcessingReport(Order $order)
{
$snapshots = [
"order-{$order->id}-processing-start",
"order-{$order->id}-discount-applied",
"order-{$order->id}-tax-calculated",
"order-{$order->id}-processing-complete"
];
$report = [];
for ($i = 0; $i < count($snapshots) - 1; $i++) {
$diff = Snapshot::diff($snapshots[$i], $snapshots[$i + 1]);
$report[] = [
'step' => $i + 1,
'from' => $snapshots[$i],
'to' => $snapshots[$i + 1],
'changes' => $diff
];
}
return $report;
}
}
Audit trail for user profile changes:
use App\Models\User;
use Grazulex\LaravelSnapshot\Traits\HasSnapshots;
class User extends Model
{
use HasSnapshots;
protected $fillable = ['name', 'email', 'profile'];
// Automatically create snapshots on important changes
protected $snapshotEvents = ['updated'];
public function updateProfile(array $profileData)
{
// Snapshot before update
$this->snapshot('profile-before-update-' . time());
// Update profile
$this->update(['profile' => array_merge($this->profile ?? [], $profileData)]);
// Snapshot after update
$this->snapshot('profile-after-update-' . time());
return $this;
}
public function getAuditTrail()
{
return $this->snapshots()
->where('label', 'like', 'profile-%')
->orderBy('created_at')
->get()
->map(function ($snapshot) {
return [
'timestamp' => $snapshot->created_at,
'label' => $snapshot->label,
'changes' => $this->getSnapshotChanges($snapshot)
];
});
}
}
Using snapshots in feature tests:
use Tests\TestCase;
use App\Models\User;
use Grazulex\LaravelSnapshot\Snapshot;
use Grazulex\LaravelSnapshot\Storage\ArrayStorage;
class UserUpdateTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
// Use memory storage for tests
Snapshot::setStorage(new ArrayStorage());
}
public function test_user_update_changes_are_tracked()
{
$user = User::factory()->create(['name' => 'Original Name']);
// Create initial snapshot
Snapshot::save($user, 'test-initial');
// Update user
$user->update(['name' => 'Updated Name']);
Snapshot::save($user, 'test-updated');
// Assert changes
$diff = Snapshot::diff('test-initial', 'test-updated');
$this->assertArrayHasKey('modified', $diff);
$this->assertArrayHasKey('name', $diff['modified']);
$this->assertEquals('Original Name', $diff['modified']['name']['from']);
$this->assertEquals('Updated Name', $diff['modified']['name']['to']);
}
public function test_user_deletion_is_tracked()
{
$user = User::factory()->create();
// Snapshot before deletion
Snapshot::save($user, 'test-before-delete');
$userId = $user->id;
$user->delete();
// Verify snapshot exists after deletion
$snapshot = Snapshot::load('test-before-delete');
$this->assertEquals($userId, $snapshot['attributes']['id']);
}
}
Implement custom storage driver:
use Grazulex\LaravelSnapshot\Contracts\SnapshotStorage;
class RedisSnapshotStorage implements SnapshotStorage
{
protected $redis;
protected $prefix;
public function __construct($redis, $prefix = 'snapshots:')
{
$this->redis = $redis;
$this->prefix = $prefix;
}
public function save(string $label, array $data): bool
{
return $this->redis->set(
$this->prefix . $label,
json_encode($data)
);
}
public function load(string $label): ?array
{
$data = $this->redis->get($this->prefix . $label);
return $data ? json_decode($data, true) : null;
}
public function delete(string $label): bool
{
return $this->redis->del($this->prefix . $label) > 0;
}
public function list(): array
{
$keys = $this->redis->keys($this->prefix . '*');
$snapshots = [];
foreach ($keys as $key) {
$label = str_replace($this->prefix, '', $key);
$data = $this->load($label);
if ($data) {
$snapshots[$label] = $data;
}
}
return $snapshots;
}
public function exists(string $label): bool
{
return $this->redis->exists($this->prefix . $label) > 0;
}
}
// Usage
$redisStorage = new RedisSnapshotStorage(app('redis')->connection());
Snapshot::setStorage($redisStorage);
Periodic automatic snapshots:
use Illuminate\Console\Command;
use App\Models\User;
use Grazulex\LaravelSnapshot\Snapshot;
class CreateScheduledSnapshots extends Command
{
protected $signature = 'snapshots:create-scheduled';
protected $description = 'Create scheduled snapshots for important models';
public function handle()
{
$timestamp = now()->format('Y-m-d-H-i-s');
// Snapshot all active users
User::where('active', true)->chunk(100, function ($users) use ($timestamp) {
foreach ($users as $user) {
Snapshot::save($user, "scheduled-user-{$user->id}-{$timestamp}");
}
});
$this->info('Scheduled snapshots created successfully');
}
}
// In app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->command('snapshots:create-scheduled')
->dailyAt('02:00')
->when(function () {
return config('snapshot.scheduled_enabled', false);
});
}
All examples can be run in several ways:
php artisan tinker
Then copy and paste any example code.
Create a custom command to run examples:
php artisan make:command RunExample
Run examples in a test case to ensure they work correctly.
For convenience, you can download the complete example files:
- basic-usage.php - Basic snapshot operations
- model-with-trait.php - Using HasSnapshots trait
- ecommerce-order-processing.php - E-commerce use case
After exploring these examples:
Laravel Snapshot - Track, store and compare Eloquent model snapshots
π Home | π Getting Started | π‘ Examples | π Full Docs
Made with β€οΈ for the Laravel community