Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Symfony Schedule Entity Clean Bundle Laravel Package

tourze/symfony-schedule-entity-clean-bundle

A Symfony bundle for scheduling automatic cleanup of Doctrine entities. It integrates with Symfony Scheduler to run periodic entity-pruning tasks, helping keep your database tidy through simple configuration and service integration in Symfony applications.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package — that's the first thing to reconcile before you install it. It ships a Bundle class, a DI extension, and Doctrine entity/repository wiring for pruning stale "schedule" entities. There is no service provider, no facade, no publishable config in the Laravel sense.

Minimal steps to evaluate whether it's worth your time:

  1. Read the bundle class and DependencyInjection/*Extension.php first — that's where the cleaning service, its interval config, and the console command (if any) are registered. Everything you can actually reuse lives there.
  2. Check composer.json for hard requirements: the symfony/* constraints, doctrine/orm, and the tourze/* sibling packages it pulls in. Sibling tourze dependencies are the usual source of surprise transitive weight.
  3. Decide which of the two integration paths you're on:
    • Symfony service available in the same codebase (mixed repo / migrating app): register the bundle and let the cleaner run as-is.
    • Pure Laravel: don't install the bundle. Copy the pruning logic (a few dozen lines of repository query + delete) into an Artisan command or a queued job. The bundle's value is the query shape and the config surface, not the packaging.
  4. First use case: schedule a daily prune of finished schedule rows older than N days, chunked, with a dry-run mode before you enable deletes.

Implementation Patterns

Port the cleaner into a command, don't bridge the bundle. In Laravel the idiomatic shape is:

class PruneSchedules extends Command
{
    protected $signature = 'schedule:prune {--days=30} {--dry-run} {--chunk=500}';

    public function handle(): int
    {
        $cutoff = now()->subDays((int) $this->option('days'));

        $query = Schedule::query()
            ->where('status', 'finished')
            ->where('updated_at', '<', $cutoff)
            ->orderBy('id');

        if ($this->option('dry-run')) {
            $this->info($query->count().' rows would be deleted');
            return self::SUCCESS;
        }

        $deleted = $query->chunkById((int) $this->option('chunk'), function ($rows) {
            Schedule::whereKey($rows->modelKeys())->delete();
        });

        return self::SUCCESS;
    }
}

Mirror the bundle's config as Laravel config. Whatever the bundle exposes (retention window, statuses eligible for cleanup, batch size), put it in config/schedule-clean.php and read it with config(). This is the piece that actually carries over — it keeps the retention policy reviewable and environment-specific.

Schedule it off-peak with withoutOverlapping(). Pruning is a write-heavy, low-value-priority job:

$schedule->command('schedule:prune')->dailyAt('03:15')->withoutOverlapping()->onOneServer();

If you're genuinely running the bundle in a Symfony app alongside a Laravel service, treat it as an external system: invoke the Symfony console command via Process from a queued job, capture exit code and stderr, and let the Symfony side own the schema. Don't let two ORMs write the same table.

Soft-delete first, hard-delete later. Two-stage is much safer for a package whose behavior you don't fully control: ->where('deleted_at', '<', $cutoff)->forceDelete() in a second, separately scheduled command.

Gotchas and Tips

  • Release 1.1.1 is an empty-changelog patch. The only artifact is a 1.1.0...1.1.1 compare link with no commit summary. Treat it as a safe patch bump, pin ^1.1.0, and diff the two tags (git log 1.1.0..1.1.1 --oneline) yourself before assuming anything. Never infer "no breaking changes" from a missing changelog on a 1.x line — check the tag diff.
  • Bundle ≠ package. composer require in a Laravel app will pull Symfony DI, HttpKernel and possibly Doctrine components you don't use. The service provider autodiscovery will not find anything useful. This is the single biggest pitfall; the rest follow from it.
  • Bundle config lives in config/packages/*.yaml. There's no php artisan vendor:publish. To see the real defaults, read the extension's load() and any Configuration.php tree — the README rarely lists them all.
  • Doctrine entity mapping vs Eloquent. The cleaner almost certainly operates on a Doctrine entity/repository. If your data lives in Eloquent, all of the persistence code is dead weight; only the retention semantics transfer.
  • Timezone and DST in retention windows. now()->subDays(30) in a DST-transition week shifts your cutoff by an hour — irrelevant for a 30-day window, but it matters if you ever use hour-level retention. Use < on a stored timestamp rather than between-style date arithmetic.
  • Chunked deletes, not ->delete() on a filtered query. A large unbounded delete will hold locks and blow up your replication lag. chunkById (not chunk) so mutated rows can't cause skips.
  • Foreign keys and cascades. Pruning a parent schedule row may cascade into logs/history. Verify ON DELETE behavior on dependent tables before enabling in production, and run the dry-run for at least one full retention cycle.
  • Debugging a silently-no-op cleaner. In Symfony, debug:container / debug:event-dispatcher tell you whether the cleaner service is actually registered and tagged. When ported to Laravel, the equivalent failure is a where clause that matches zero rows — log the pre-delete count every run, not just the deletion count.
  • Watch the tourze/* dependency chain. These bundles frequently depend on several siblings, each with their own release cadence. Pin them together and upgrade as a group; a single patch on one sibling is where breakage actually shows up.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json
refinery29/php-cs-fixer-config
hotmeteor/eco-env
mvaliolahi/hydrate
wearede/tbcpay-php
parsnick/steak
thibaud-dauce/mattermost-php
multilinguals/apollo-client
antaresbr/collection
kr0lik/phpstan-rules