motomedialab / compliance
A package for enforcing GDPR compliance rules
Requires
- php: ^8.0
- laravel/framework: ^10.0|^11.0|^12.0
Requires (Dev)
- larastan/larastan: ^2.0|^3.0
- laravel/pint: ^1.18
- orchestra/testbench: ^7.0|^8.0|^9.0|^10.0
- pestphp/pest: ^2.0|^3.0
This package is auto-updated.
Last update: 2025-06-16 16:01:05 UTC
README
In today's world of data privacy regulations like GDPR, you can't hold onto user data forever. But manually tracking and deleting old records is a headache waiting to happen. Compliance is a configurable Laravel package that automates this process, ensuring you stay on the right side of the law by effortlessly deleting records that are no longer needed.
Think of it as a fire-and-forget solution for data retention. Set up your rules, and let Compliance handle the rest.
How It Works: The Two-Step Deletion Process
Compliance operates on a safe, two-step cycle to ensure records are never deleted by mistake. This gives you a grace period to act, for instance, by notifying a user that their account is about to be removed.
-
The Check (
artisan compliance:check
):- Every day, a scheduled command runs through your specified models (like
User
). - It looks for records that meet your defined deletion criteria (e.g., users who haven't logged in for 3 years).
- When a record matches, Compliance creates a
ComplianceCheck
entry in your database, marking the record with a future deletion date. - At this point, the
ComplianceRecordPendingDeletion
event is fired. This is your chance to hook in and, for example, send a notification email.
- Every day, a scheduled command runs through your specified models (like
-
The Prune (
artisan compliance:prune
):- A second daily command scans for
ComplianceCheck
records where the deletion date has passed. - It performs a final check on the model to ensure it still meets the deletion criteria. This is a safety net... If a user logs in after being marked for deletion, their account will be spared.
- If the criteria are still met, the
ComplianceDeleting
event is fired just before the model is permanently deleted.
- A second daily command scans for
Installation
Getting started is easy, just follow these three steps...
-
Install via Composer:
composer require motomedialab/compliance
-
Publish Configuration & Run Migrations: Publish the configuration file to specify which models to monitor. Then, run the migrations to create the
compliance_checks
table.php artisan vendor:publish --provider="Motomedialab\Compliance\Providers\ComplianceServiceProvider" --tag="config" php artisan migrate
Quick Start: The Basic User Model
Out of the box, the package is configured to handle a typical User
model. Just implement the HasCompliance
contract and use the ComplianceRules
trait.
// app/Models/User.php namespace App\Models; use Motomedialab\Compliance\Traits\Compliance; use Motomedialab\Compliance\Contracts\HasCompliance; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable implements HasCompliance { use Compliance; // ... your other model code }
Next, add your User
model to the config/compliance.php
file.
// config/compliance.php return [ 'models' => [ App\Models\User::class => [ // The column to check 'column' => 'last_login_at', // How old the record must be to be considered for deletion 'delete_after_days' => 365 * 3, // 3 years // The grace period between being marked and being deleted 'deletion_grace_period' => 15 // 15 days ], ], ];
And that's it! The package will now automatically schedule users for deletion if their last_login_at
date is over three years old.
Advanced Scenarios & Powerful Examples
The real power of this package lies in its flexibility. You can override several methods from the ComplianceRules
trait to build highly custom logic.
Example 1: Deleting Only Users Who Have Never Logged In
You might want to clean up accounts that were created but never used. You can override the complianceQueryBuilder
method to define a completely custom query.
// app/Models/User.php use Illuminate\Database\Eloquent\Builder; class User extends Authenticatable implements HasCompliance { use Compliance; /** * Override the default query to only find users who have never logged in. */ public function complianceQueryBuilder(): Builder { // Use the newQuery() method on the model for a clean builder instance. return $this->newQuery()->whereNull('last_login_at'); } }
Example 2: Protecting VIPs or Active Subscribers
You never want to accidentally delete a paying customer. The complianceMeetsDeletionCriteria
method is your
safety check, which runs both during the initial check and right before the final deletion.
// app/Models/User.php class User extends Authenticatable implements HasCompliance { use Compliance; /** * This method is the final gatekeeper. * Only return true if the record can be safely deleted. */ public function complianceMeetsDeletionCriteria(): bool { // Don't delete if the user is an admin or has an active subscription. if ($this->is_admin || $this->hasActiveSubscription()) { return false; } return true; } }
Example 3: Notifying Users of Pending Deletion
Compliance fires events to let you hook into the lifecycle. Here’s how you can listen for the ComplianceRecordPendingDeletion
event to email a user.
First, create a listener:
php artisan make:listener NotifyUserOfPendingDeletion
Then, register it in your EventServiceProvider
:
// app/Providers/EventServiceProvider.php protected $listen = [ \Motomedialab\Compliance\Events\ComplianceRecordPendingDeletion::class => [ \App\Listeners\NotifyUserOfPendingDeletion::class, ], ];
Finally, implement the listener's logic:
// app/Listeners/NotifyUserOfPendingDeletion.php namespace App\Listeners; use Illuminate\Support\Facades\Mail; use App\Mail\AccountDeletionWarning; use Motomedialab\Compliance\Events\ComplianceRecordPendingDeletion; class NotifyUserOfPendingDeletion { public function handle(ComplianceRecordPendingDeletion $event): void { $user = $event->record->model; $deletionDate = $event->record->deletion_date; // Send an email to the user Mail::to($user)->send(new AccountDeletionWarning($user, $deletionDate)); } }
Example 4: Cleaning Up Old Log Entries
This package isn't just for users. You can apply it to any model. Imagine you have a Log
model and you only want to keep records for 90 days.
// config/compliance.php 'models' => [ // ... other models App\Models\Log::class => [ 'column' => 'created_at', 'delete_after_days' => 90, 'deletion_grace_period' => 0 // Delete immediately ], ],
Then, simply apply the trait and interface to your Log
model.
// app/Models/Log.php namespace App\Models; use Motomedialab\Compliance\Traits\Compliance; use Motomedialab\Compliance\Contracts\HasCompliance; use Illuminate\Database\Eloquent\Model; class Log extends Model implements HasCompliance { use Compliance; }