simone-bianco/laravel-patches

Laravel package to manage patches for your application, like database migrations but for code.

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 1

Forks: 0

Open Issues: 0

pkg:composer/simone-bianco/laravel-patches

1.0.0 2025-09-27 13:27 UTC

This package is auto-updated.

Last update: 2025-09-27 13:45:23 UTC


README

This package provides a robust, migration-like system for managing incremental data changes in your Laravel application. Instead of messy, non-repeatable seeders, you can create timestamped "patch" files that are tracked in the database, can be rolled back, and can be organized into subdirectories.

It's the perfect solution for:

  • Seeding initial application data (like user roles, settings, countries, etc.).
  • Deploying data changes to a production environment in a controlled and reversible way.
  • Organizing complex data modifications into logical, ordered steps.

Installation

You can install the package via composer:

composer require simonebianco/laravel-patches

Next, you should publish the package's assets (configuration file and migration):

php artisan vendor:publish --provider="SimoneBianco\Patches\PatchesServiceProvider"

This will publish:

  • A configuration file to config/patches.php.
  • A migration file to database/migrations/.

Finally, run the migration to create the data_patches table, which will track the executed patches.

php artisan migrate

Configuration ⚙️

The configuration file config/patches.php allows you to define global hooks that run before and after the patch processes. This is useful for tasks like disabling model observers during execution or clearing the application cache afterward.

Each hook must be a fully qualified class name that contains an __invoke method.

// config/patches.php

return [
    'callbacks' => [
        'up' => [
            // Executed before `patch:apply` starts
            'before' => null, 
            // Executed after `patch:apply` finishes
            'after' => App\Patches\Hooks\ClearCache::class, 
        ],
        'down' => [
            // Executed before `patch:rollback` starts
            'before' => null,
            // Executed after `patch:rollback` finishes
            'after' => null,
        ],
    ],
];

Example Hook Class

// app/Patches/Hooks/ClearCache.php

namespace App\Patches\Hooks;

use Illuminate\Support\Facades\Artisan;

class ClearCache
{
    public function __invoke(): void
    {
        Artisan::call('cache:clear');
        Artisan::call('config:clear');
    }
}

Directory structure

Below is an example structure for organizing your patches. You can nest as deep as you need:

Directory structure

Usage

1. Creating a Patch

To create a new patch, use the make:patch Artisan command. The patch files will be stored in the database/patches directory.

php artisan make:patch seed_initial_roles_and_permissions

This will create a file with the naming convention YYYY_MM_DD_XXXXXX_seed_initial_roles_and_permissions.php.

You can also create patches in subdirectories for better organization:

php artisan make:patch settings/site/add_maintenance_mode_setting

This will create the file inside database/patches/settings/site/.

2. The Patch File Structure

Each patch file is a simple class with two methods: up() and down().

  • up(): Contains the logic to apply the data change.
  • down(): Contains the logic to reverse the change.
<?php

use Spatie\Permission\Models\Role; // Example using a popular package

class SeedInitialRolesAndPermissions
{
    /**
     * Run the data patch.
     */
    public function up(): void
    {
        Role::create(['name' => 'admin']);
        Role::create(['name' => 'editor']);
    }

    /**
     * Reverse the data patch.
     */
    public function down(): void
    {
        Role::whereIn('name', ['admin', 'editor'])->delete();
    }
}

Transactions (optional)

If you need your patch to run inside a single database transaction, set the public $transactional flag on your patch class. When true, the runner will wrap up() and down() in a DB transaction.

<?php

use SimoneBianco\Patches\Patch;

return new class extends Patch
{
    public bool $transactional = true; // run inside a transaction

    public function up(): void
    {
        // ... data changes
    }

    public function down(): void
    {
        // ... reverse data changes
    }
};

Note: transactions are disabled by default (false). Enable them only when you need all operations in the patch to succeed or fail together.

3. Applying Patches ⚡️

To run all pending patches that haven't been executed yet, use the patch:run command. The system will find all .php files recursively, sort them alphabetically by path, and execute them in order.

php artisan patch:run

You can also limit how many patches are applied in one run using the --step option:

php artisan patch:run --step=1

Forcing a Single Patch

For debugging or testing purposes, you can force-run a single patch, even if it has already been applied. This command does not record the execution in the tracking table.

The patch name is its path relative to the patches directory.

php artisan patch:single settings/site/2025_09_25_000001_add_maintenance_mode_setting

Re-apply from scratch (fresh)

Roll back applied patches and re-apply all pending patches in one go:

php artisan patch:fresh

4. Rolling Back Patches ↩️

The patch:rollback command is powerful and flexible, mirroring Laravel's migrate:rollback.

Roll Back the Last Batch

This is the default behavior. It will roll back all patches that were applied in the last patch:run run.

php artisan patch:rollback

Roll Back by Steps

To roll back a specific number of the most recently applied patches, regardless of their batch, use the --step option.

php artisan patch:rollback --step=3

Roll Back All Patches

To roll back every single patch that has been applied, use the --all option. This is a destructive operation.

php artisan patch:rollback --all

5. Production Safety ⚠️

Running a rollback in a production environment is risky. Therefore, if your APP_ENV is set to production, the patch:rollback command will prompt you for confirmation before executing.

To bypass this confirmation in your deployment scripts, use the --force flag.

php artisan patch:rollback --step=1 --force

6. Advanced Usage: Using the Facade

You can also trigger the patch operations directly from your application code using the Patches facade.

use SimoneBianco\Patches\Facades\Patches;

// Apply all pending patches
$patchesRun = Patches::runPatches();

// Roll back the last batch
$rolledBackCount = Patches::rollback();

// Roll back 5 steps
$rolledBackCount = Patches::rollback(['step' => 5]);

// Create a new patch file programmatically
$filePath = Patches::createPatch('update_user_country_codes');

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review [link sospetto rimosso] on how to report security vulnerabilities.

License

The MIT License (MIT). Please see License File for more information.