Pruning Models in Eloquent: Tutorial & Examples

Updated: January 16, 2024 By: Guest Contributor Post a comment

Introduction

Eloquent ORM is a powerful and advanced database tool native to Laravel, enabling developers to perform complex database operations with minimal effort. In this tutorial, we’ll cover how you can prune or clean up your Eloquent models. This functionality is extremely useful when you want to maintain lean and efficient tables by purging outdated or irrelevant records.

Before we start, ensure that you have a Laravel environment set up and ready to go. You’ll also need a database connection configured in your ‘.env’ file so that Eloquent can interact with your database.

Understanding Model Pruning

Pruning your Eloquent Models can help reduce the size of your database by deleting records that are no longer needed. The latest versions of Laravel allow scheduling periodic cleaning operations directly through Eloquent, however manual pruning is also possible.

We will first cover the automatic approach and then delve into how to manually invoke the pruning process when needed.

Automatic Pruning

To automatically prune your models, you’ll need to use Laravel’s scheduling capabilities. This is done in the app/Console/Kernel.php file.

use App\Models\YourEloquentModel;

protected function schedule(Schedule $schedule)
{
    $schedule->command('model:prune', [
        '--model' => [YourEloquentModel::class],
    ])->daily();
}

In the example above, replace YourEloquentModel with the actual model class you wish to prune. The --model option specifies which models to include in the pruning process, and we’ve scheduled this command to run daily.

Implementing Prunable Trait

For a model to be eligible for pruning, it needs to use the Illuminate\Database\Eloquent\Prunable trait and provide a prunable() method that defines the pruning logic:

use Illuminate\Database\Eloquent\Prunable;

class YourEloquentModel extends Model
{
    use Prunable;

    public function prunable()
    {
        return static::where('created_at', '<=', now()->subYear());
    }
}

This example defines a prunable method that scopes the query to select records created more than a year ago. These records will be the ones eligible for pruning.

Advanced Pruning Conditions

Pruning conditions are not limited to dates; you can specify any condition you would typically use with Eloquent:

public function prunable()
{
    return static::where('status', 'archived')->orWhere('views', '<', 100);
}

Be cautious with your pruning conditions. Once records are pruned, they are permanently deleted from the database.

Running Pruning Manually

If you need to trigger the pruning process manually or through a route/controller, you can call the prune method directly on your model:

$prunedRecordsCount = YourEloquentModel::prune();

This will execute the pruning operation according to the logic defined in your prunable method and return the number of records affected.

Advanced Usage

Let’s explore some advanced practices that you might need when dealing with large data sets or when looking to have more control over pruning operations.

Overriding Default Pruning Behavior

Sometimes, you may want to change the default behavior of the pruning operation. For instance, to include a soft delete instead of permanently deleting the records:

public function prunable()
{
    return static::onlyTrashed()->where('deleted_at', '<', now()->subMonth());
}

This code will prune only the soft-deleted records that have been deleted for over a month, assuming your model is also using the SoftDeletes trait.

Scheduling with Complex Criteria

If you have complex pruning requirements that involve relationships, you can extend the system with custom commands:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\User;

class PruneInactiveUsers extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'users:prune-inactive';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Prune inactive user accounts.';

    public function handle()
    {
        User::whereDoesntHave('logins', function ($query) {
            $query->where('created_at', '>', now()->subYear());
        })->prune();

        $this->info('Inactive users pruned successfully.');
    }
}

The above command prunes users that haven’t logged in for over a year. Make sure to register your new command in the app/Console/Kernel.php file:

protected $commands = [
    Commands\PruneInactiveUsers::class,
];

Events and Observers

With pruning operations, you might sometimes need to perform additional clean-up tasks. Laravel provides events which you can utilize by implementing an observer. Here’s how you can listen to the pruning event:

YourEloquentModel::observe(YourObserver::class);

Inside your observer, you can define a method pruning that will be called before the records are deleted, or pruned for after:

public function pruning($model)
{
    // Code to execute before each model is pruned
}

public function pruned($model)
{
    // Code to execute after each model is pruned
}

Remember that these observers will work at a model instance level, so if you’re pruning large numbers of records, consider the potential performance impacts.

Conclusion

This tutorial has walked you through the process of setting up pruning for your Eloquent models, from simple date-based conditions to complex criteria involving relationships and custom commands. Pruning improves application performance by keeping tables optimized and removes clutter. It’s an essential technique for maintaining large and dynamic datasets efficiently.