1. Go to this page and download the library: Download heyosseus/difflock library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
heyosseus / difflock example snippets
Schema::table('users', function (Blueprint $table) {
$table->string('status'); // fails on a populated table
$table->dropColumn('legacy_token'); // no down() brings the data back
$table->renameColumn('name', 'full_name'); // breaks the release still running
});
// config/difflock.php
// 1. Exclude tables entirely — they appear in no diff and reach no file.
'ignore' => ['tables' => ['oauth_*', 'personal_access_tokens']],
// 2. Or keep the tables and drop the only two fields that carry free text.
'snapshot' => ['defaults' => false, 'comments' => false],
RiskLevel::Safe // nothing here can lose data or break a running application
RiskLevel::Low // reversible, unlikely to be felt
RiskLevel::Medium // reversible, capable of noticeable impact on a busy table
RiskLevel::High // can break the running application, or fail partway through
RiskLevel::Critical // destroys data or structure no down() brings back
use Difflock\Contracts\MigrationRule;
use Difflock\Migration\MigrationContext;
use Difflock\Migration\Subject;
use Difflock\Risk\RiskLevel;
final class NoUuidPrimaryKeysRule implements MigrationRule
{
public function identifier(): string
{
return 'no-uuid-primary-keys';
}
public function analyze(MigrationContext $context): array
{
$findings = [];
foreach ($context->operations('uuid') as $operation) {
if (! $operation->hasModifier('primary')) {
continue;
}
$findings[] = $context->finding(
rule: $this->identifier(),
risk: RiskLevel::Medium,
message: 'UUID primary key on '.$context->tableName(),
explanation: 'Random primary keys scatter inserts across the index.',
suggestion: 'Use an auto-incrementing key, or a ULID.',
subject: $operation->stringArgument(0),
subjectType: Subject::Column,
operation: $operation,
);
}
return $findings;
}
}
// A service provider's boot()
use Difflock\Facades\Difflock;
Difflock::rule(NoUuidPrimaryKeysRule::class);
$context->migrationName(); // '2026_08_10_120000_remove_legacy_token'
$context->tableName(); // 'users', or null if it was not a literal
$context->liveTable(); // the table as it exists now, or null
$context->rows(); // roughly how many rows, or null if unknown
$context->reversible(); // whether down() has a body
$context->operations('index'); // the blueprint chains starting with index()
$context->database->thresholds;
$context->database->available; // false when there was no database to ask
use Difflock\Database\FixedTableStatistics;
$statistics = new FixedTableStatistics(['orders' => 8_421_392]);
use Difflock\Facades\Difflock;
$schema = Difflock::inspect(); // the live schema
$diff = Difflock::diff('a', 'b'); // two connections compared
$drift = Difflock::drift(); // live vs recorded baseline
$report = Difflock::analyze(); // the whole migration report
$findings = Difflock::lint(); // just the findings
$decision = Difflock::guard(); // should the pending migrations run?
use Difflock\Contracts\MigrationAnalyzer;
use Difflock\Contracts\SchemaDiffer;
public function __construct(
private MigrationAnalyzer $analyzer,
private SchemaDiffer $differ,
) {}
if (config('features.phone')) { // may or may not run
Schema::table(...);
}
foreach ($this->tenantTables() as $t) { // table names unknown
Schema::table($t, ...);
}
DB::statement('ALTER TABLE ...'); // not read at all
bash
php artisan difflock:lint # pending migrations
php artisan difflock:lint --all # every migration file
php artisan difflock:lint --accept # record what it found as accepted
php artisan difflock:lint --path=database/migrations/legacy