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

Doctrine Garbage Collection Bundle Laravel Package

22h/doctrine-garbage-collection-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation Add the bundle via Composer:

    composer require 22h/doctrine-garbage-collection-bundle
    

    Enable it in config/bundles.php:

    return [
        // ...
        DoctrineGarbageCollectionBundle::class => ['all' => true],
    ];
    
  2. Configuration Publish the default config:

    php bin/console doctrine:garbage-collection:install
    

    Edit config/packages/doctrine_garbage_collection.yaml to define:

    • entities: List of entities to clean (e.g., App\Entity\LogEntry).
    • ttl: Time-to-live in seconds (e.g., 86400 for 1 day).
    • batch_size: Number of records to delete per batch (e.g., 1000).
  3. First Run Execute the garbage collection manually:

    php bin/console doctrine:garbage-collection:run
    

    Verify logs in var/log/dev.log for deleted records.


First Use Case: Cleaning Old Logs

# config/packages/doctrine_garbage_collection.yaml
doctrine_garbage_collection:
    entities:
        App\Entity\LogEntry:
            ttl: 2592000  # 30 days
            batch_size: 500
            condition: "logLevel < 400"  # Optional: Custom DQL condition

Run via CLI or schedule a cron job:

php bin/console doctrine:garbage-collection:run App\Entity\LogEntry

Implementation Patterns

Workflow: Integrating with Laravel

  1. Service Provider Setup Register the bundle in config/app.php (Symfony bundles require manual integration in Laravel):

    'providers' => [
        // ...
        DoctrineGarbageCollectionBundle::class,
    ],
    
  2. Command Integration Create a Laravel Artisan command to wrap the Symfony command:

    // app/Console/Commands/GarbageCollection.php
    namespace App\Console\Commands;
    
    use Illuminate\Console\Command;
    use Symfony\Component\Console\Application;
    
    class GarbageCollection extends Command
    {
        protected $signature = 'doctrine:gc {entity?}';
        protected $description = 'Run Doctrine garbage collection';
    
        public function handle()
        {
            $app = new Application();
            $app->add(new \DoctrineGarbageCollectionBundle\Command\GarbageCollectionCommand());
            $app->setAutoExit(false);
            $app->run(new \Symfony\Component\Console\Input\ArrayInput([
                'command' => 'doctrine:garbage-collection:run',
                'entity' => $this->argument('entity'),
            ]));
        }
    }
    
  3. Scheduling Add to app/Console/Kernel.php:

    protected function schedule(Schedule $schedule)
    {
        $schedule->command('doctrine:gc')->dailyAt('03:00');
    }
    

Advanced Patterns

  1. Dynamic TTL Override TTL per environment using Laravel’s config:

    # config/doctrine_garbage_collection.php
    ttl:
        default: 86400
        production: 604800  # 1 week
    

    Modify the bundle’s config loader to merge with Laravel’s config.

  2. Event-Based Triggers Hook into Laravel events (e.g., user.deleted) to trigger garbage collection:

    // app/Providers/EventServiceProvider.php
    public function boot()
    {
        event(new \App\Events\UserDeleted());
    }
    

    Listen in a service:

    // app/Services/GarbageCollectionService.php
    public function handle(UserDeleted $event)
    {
        $this->callGarbageCollection('App\Entity\TempFile');
    }
    
  3. Custom Conditions Use DQL in config for complex logic:

    condition: "createdAt < :date AND status = 'archived'"
    

    Pass parameters via parameters key:

    parameters:
        date: "now() - interval '30 days'"
    

Gotchas and Tips

Pitfalls

  1. Transaction Management

    • The bundle runs in a single transaction by default. For large datasets, split into smaller transactions or disable transactions:
      transactional: false
      
    • Risk: Unhandled exceptions may leave the database in an inconsistent state.
  2. Foreign Key Constraints

    • Ensure soft-deleted entities are excluded or cascaded properly. Use ON DELETE CASCADE in migrations if needed.
    • Debug Tip: Run with --dry-run to preview deletions:
      php bin/console doctrine:garbage-collection:run --dry-run
      
  3. Performance Impact

    • Large batch_size values may lock tables. Start with 100 and monitor.
    • Symptom: Slow queries or timeouts suggest batch size is too large.
  4. Symfony vs. Laravel Quirks

    • Service Container: The bundle expects Symfony’s DI. Use Laravel’s SymfonyBridge or mock services:
      $container = new \Symfony\Component\DependencyInjection\Container();
      $container->set('doctrine', $this->app->make('doctrine'));
      
    • Logging: Logs may appear in Symfony’s var/log/ instead of Laravel’s storage/logs/. Redirect via monolog config.

Debugging Tips

  1. Enable Verbose Output

    php bin/console doctrine:gc --verbose
    

    Look for:

    • Deleting X records from App\Entity\Y
    • Query: DELETE FROM ... WHERE ...
  2. Check for Orphaned Records Use Doctrine’s query builder to verify:

    $em->createQueryBuilder()
        ->select('e')
        ->from('App\Entity\LogEntry', 'e')
        ->where('e.createdAt < :date')
        ->setParameter('date', new \DateTime('-30 days'))
        ->getQuery()
        ->getResult();
    
  3. Handle Soft Deletes If using SoftDeletes, exclude the entity from garbage collection or override the delete() method:

    // In your entity
    public function delete()
    {
        $this->setDeletedAt(new \DateTime());
        $this->em->persist($this);
        $this->em->flush();
    }
    

Extension Points

  1. Custom Collectors Extend \DoctrineGarbageCollectionBundle\Collector\CollectorInterface:

    class CustomCollector implements CollectorInterface
    {
        public function collect(EntityManagerInterface $em, string $entityClass, array $config)
        {
            // Custom logic (e.g., call an external API)
            return $em->createQueryBuilder()
                ->delete($entityClass, 'e')
                ->where('e.customField = :value')
                ->getQuery();
        }
    }
    

    Register in config:

    collectors:
        custom:
            class: App\Collector\CustomCollector
            entities: [App\Entity\CustomEntity]
    
  2. Pre/Post Hooks Use Laravel’s events to run logic before/after garbage collection:

    // Listen to doctrine.gc.before
    event(new \App\Events\GarbageCollectionStarting('App\Entity\LogEntry'));
    
    // Listen to doctrine.gc.after
    event(new \App\Events\GarbageCollectionCompleted('App\Entity\LogEntry', 42));
    
  3. Database-Specific Optimizations Add hints for PostgreSQL/MySQL:

    options:
        mysql: { hint: "/*+ INDEX_SCAN(table_idx) */" }
        pgsql: { hint: "/*+ IndexScan(table_idx) */" }
    

Pro Tips

  • Backup First: Always back up before running garbage collection on production.
  • Monitor with Laravel Scout: Track deleted records in a deleted_at table and index it for Scout.
  • Combine with Laravel Housekeeping: Use packages like spatie/laravel-housekeeping for a unified approach.
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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels