nti/auto-delete-bundle
Automatically removes expired or stale records from your application, letting you schedule deletions and keep database tables clean without manual cleanup jobs.
nti/auto-delete-bundle is a Symfony bundle, not a Laravel package — there is no AutoDeleteServiceProvider, no facade, and no Laravel config publishing. Treat it as an integration project rather than a composer require-and-go dependency.
Minimal steps to evaluate it:
DependencyInjection/NTIAutoDeleteExtension.php or similar). This tells you the config tree — what TTL/entity options exist and their defaults. This is the only reliable source of truth at 0 stars.Command/). The bundle's day-to-day value is a single command that purges stale records; identify its name, options (dry-run, entity filter, batch size), and exit behavior.AutoDeleteInterface or a PHP attribute/annotation you put on a Doctrine entity. That contract is what a Laravel port must replicate.If you are Laravel-only, the honest first step is to decide whether you are running Symfony side-by-side (unusual but possible via a small console kernel) or reimplementing the pattern. For most Laravel apps the latter is faster and safer.
Symfony-native usage (intended path).
// config/bundles.php
NTI\AutoDeleteBundle\NTIAutoDeleteBundle::class => ['all' => true],
# config/packages/nti_auto_delete.yaml
nti_auto_delete:
entities:
App\Entity\Notification: { ttl: '30 days' }
App\Entity\AuditLog: { ttl: '90 days' }
Then schedule the command (crontab or Symfony Scheduler). Entities must implement the bundle's marker contract, so the deletion query can be scoped generically.
Porting the pattern to Laravel (recommended). The bundle's value is conceptual, not code. Replicate it with native tools:
// app/Console/Commands/PurgeAutoDelete.php
class PurgeAutoDelete extends Command
{
protected $signature = 'autodelete:run {--dry-run} {--model=}';
public function handle(): int
{
foreach (config('autodelete.models') as $model => $days) {
$query = $model::where('created_at', '<', now()->subDays($days));
$this->option('dry-run')
? $this->info("$model: ".$query->count().' rows')
: $query->chunkById(1000, fn ($rows) => $model::whereKey($rows->modelKeys())->delete());
}
return self::SUCCESS;
}
}
// app/Console/Kernel.php
$schedule->command('autodelete:run')->dailyAt('03:00')->withoutOverlapping();
Integration tip: If you must consume the bundle directly, wrap it behind a thin adapter — one Laravel command that boots a minimal Symfony container and delegates to the bundle's service. Keep the adapter small so a future fork or reimplementation is a drop-in swap.
Deletion semantics: Decide up front whether "delete" means soft-delete, hard-delete, or anonymize. The bundle likely hard-deletes via Doctrine; in Laravel you will often want forceDelete() or a mass update that nulls PII columns rather than removing rows, especially if foreign keys or audit requirements exist.
composer.json, fork it, or vendor the logic. Do not make it a critical path dependency without a fallback.now() in app timezone vs. database created_at in UTC can delete a day early or late. Assert the boundary in a test.withoutOverlapping() so a slow run doesn't stack.SoftDeletes, the global scope excludes trashed rows — purges targeting "old deleted records" may match nothing until you call withTrashed(). Check this first when counts look wrong.config/bundles.php, run bin/console cache:clear, check var/log/ for query errors, and inspect the generated SQL via the Doctrine profiler or -vvv on the command.How can I help you explore Laravel packages today?