<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
mueller-schmitz / laravel-model-integrity example snippets
use Illuminate\Database\Eloquent\Model;
use MuellerSchmitz\ModelIntegrity\Concerns\HasIntegrity;
class Invoice extends Model
{
use HasIntegrity;
protected string $integrityMode = 'versioned'; // 'versioned' | 'immutable'
protected string $integrityDeletes = 'record'; // 'forbid' | 'record'
protected array $integrityExcept = ['updated_at']; // not part of snapshots
protected array $integrityRelations = ['tags']; // related keys are part of every snapshot
protected int $integritySchemaVersion = 1; // bump when the snapshot structure changes
}
use MuellerSchmitz\ModelIntegrity\ModelIntegrity;
ModelIntegrity::actingAs($user, fn () => $invoice->update([...]));
ModelIntegrity::actingAs('system'); // a label instead of a model
use MuellerSchmitz\ModelIntegrity\Casts\AsIntegrityFile;
use MuellerSchmitz\ModelIntegrity\Facades\IntegrityFiles;
// Migration: $table->char('pdf', 64)->nullable();
class Invoice extends Model
{
use HasIntegrity;
protected function casts(): array
{
return ['pdf' => AsIntegrityFile::class];
}
}
$invoice->update(['pdf' => IntegrityFiles::store($request->file('pdf'))]);
$invoice->pdf->sha256; // the column holds the hash, which is part of the snapshot
$invoice->pdf->readStream();
$invoice->pdf->contents();
IntegrityFiles::find($sha256);
class Order extends Model
{
use HasIntegrity;
protected array $integrityPersonal = ['shipping_name', 'shipping_address'];
protected array $integrityAnonymized = ['shipping_name' => '']; // allowed after shredding, besides null
public function integritySubject(): ?Model // default: the model itself
{
return $this->customer;
}
}
use MuellerSchmitz\ModelIntegrity\Facades\IntegritySubjects;
IntegritySubjects::shred($customer, 'Erasure request #42'); // or: php artisan model-integrity:shred "App\Models\Customer" 42 --reason="..."
IntegritySubjects::isShredded($customer);
$version->revealedSnapshot()->snapshot; // personal attributes decrypted, null once shredded
$version->revealedSnapshot()->shredded; // the attributes whose key was shredded
DB::transaction(function () use ($post, $tagIds) {
$post->tags()->sync($tagIds);
$post->recordRelation('tags');
});
$invoice->integrityVersions()->get(); // query builder, oldest first
$invoice->history(); // collection, see Verification
use MuellerSchmitz\ModelIntegrity\Facades\IntegrityChecker;
$result = IntegrityChecker::checkModel($invoice);
$result->passes();
$result->fails();
$result->errors(); // Collection<IntegrityError>
$result->checkedVersions();
$result->lastValidVersion(); // the chain is intact up to this version
IntegrityChecker::getHistory($invoice); // Collection<Version>, oldest first
IntegrityChecker::getHistory($invoice, verify: true); // each version with ->isValid()
IntegrityChecker::versionAt($invoice, '2026-03-01'); // version current at that moment
IntegrityChecker::checkType(Invoice::class); // all invoices, including deleted ones
IntegrityChecker::checkChain(); // the global chain over all models
IntegrityChecker::checkAll(); // global chain, anchors and every recorded model
IntegrityChecker::checkAnchors(); // the anchors against the versions and their proofs
IntegrityChecker::checkFiles(); // hashes the content of every stored file
// routes/console.php
use Illuminate\Support\Facades\Schedule;
Schedule::command('model-integrity:verify')->dailyAt('03:00')->emailOutputOnFailure('[email protected]');