Weave Code
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 Extra Laravel Package

draw/doctrine-extra

Adds extra helpers and integrations for using Doctrine within Laravel/PHP apps, including convenience utilities to extend Doctrine’s capabilities and streamline configuration and common tasks.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation Require the package via Composer:

    composer require draw/doctrine-extra
    

    Ensure your project meets the PHP 8.5+ requirement and has Doctrine ORM (v3.6+) or Doctrine DBAL (v4.4+) installed.

  2. First Use Case: Basic Query Logging Register the DoctrineExtraLogger in your Doctrine ORM configuration (e.g., config/packages/doctrine.yaml):

    doctrine:
        orm:
            entity_listeners:
                Draw\DoctrineExtra\Logger\DoctrineExtraLogger: ~
    

    Configure Monolog to capture logs (if not already set up):

    monolog:
        handlers:
            doctrine_extra:
                type: stream
                path: "%kernel.logs_dir%/doctrine.log"
                level: debug
                channels: ["doctrine"]
    
  3. Enable Logging in Code Use the logger directly in repositories or services:

    use Draw\DoctrineExtra\Logger\DoctrineExtraLogger;
    
    $logger = new DoctrineExtraLogger($entityManager, $monologLogger);
    $logger->logQuery('SELECT * FROM users'); // Log a custom query
    

Implementation Patterns

Logging Doctrine Events

Leverage Doctrine's event system to log entity operations (e.g., prePersist, preUpdate):

use Draw\DoctrineExtra\Logger\DoctrineExtraLogger;
use Doctrine\ORM\Event\LifecycleEventArgs;

class UserRepository
{
    public function save(User $user, bool $flush = false): void
    {
        $logger = new DoctrineExtraLogger($this->entityManager, $this->monologLogger);
        $logger->logEntityEvent('prePersist', $user, $args);

        parent::save($user, $flush);
    }
}

Query Profiling

Log SQL queries with execution time for performance analysis:

use Draw\DoctrineExtra\Logger\QueryLogger;

$logger = new QueryLogger($entityManager, $monologLogger);
$logger->startQueryTimer(); // Start timing a query
$users = $this->entityManager->createQuery('SELECT u FROM User u')->getResult();
$logger->endQueryTimer('User query'); // Log execution time

Integration with Monolog Handlers

Extend Monolog to process Doctrine logs:

use Draw\DoctrineExtra\Logger\DoctrineExtraHandler;

$handler = new DoctrineExtraHandler($entityManager, 'doctrine.log');
$monolog->pushHandler($handler);

Workflow: Debugging Entity Relationships

  1. Log Relationships: Use DoctrineExtraLogger to log entity associations:
    $logger->logEntityRelationship($entity, 'manyToOne', 'User');
    
  2. Visualize with Graphviz: Generate a DOT file for relationships (requires draw/graphviz):
    $graphvizLogger = new GraphvizLogger($entityManager);
    $dot = $graphvizLogger->generateDot($entityManager->getClassMetadata(User::class));
    file_put_contents('user_relationships.dot', $dot);
    
  3. Render the Graph: Convert the DOT file to an image using dot -Tpng user_relationships.dot -o user_relationships.png.

Workflow: Auditing Sensitive Operations

  1. Log Mass Updates/Deletes: Override repository methods to log bulk operations:
    public function removeAllInactiveUsers(): void
    {
        $logger = new DoctrineExtraLogger($this->entityManager, $this->monologLogger);
        $logger->logMassOperation('DELETE', User::class, ['active' => false]);
    
        $this->createQueryBuilder('u')
             ->delete()
             ->where('u.active = :active')
             ->setParameter('active', false)
             ->getQuery()
             ->execute();
    }
    
  2. Filter Logs in Monolog: Route audit logs to a dedicated channel:
    monolog:
        channels: ['audit']
        handlers:
            audit:
                type: fingers_crossed
                action_level: error
                handler: stream
                formatter: monolog.formatter.json
    

Gotchas and Tips

Pitfalls

  1. PHP Version Strictness The package enforces PHP 8.5+, which may conflict with Laravel's default PHP version (e.g., 8.2 in Laravel 10). Use a .php-version file or adjust your Laravel setup:

    echo "8.5" > .php-version
    
  2. Doctrine Event Conflicts Multiple listeners on the same event (e.g., prePersist) may cause race conditions. Prioritize listeners in config/packages/doctrine.yaml:

    doctrine:
        orm:
            entity_listeners:
                Draw\DoctrineExtra\Logger\DoctrineExtraLogger: 100 # Higher priority
                App\CustomListener: 200
    
  3. Graphviz Dependencies The GraphvizLogger requires:

    • The graphviz PHP extension (pecl install graphviz).
    • System-wide Graphviz tools (dot, neato). Test locally:
    dot -V  # Should return version info
    
  4. Log Bloat Logging every query or entity operation can generate GBs of logs. Use environment-based filtering:

    $logger = new DoctrineExtraLogger($entityManager, $monologLogger);
    if (!app()->environment('local')) {
        $logger->setEnabled(false);
    }
    
  5. Circular References in Graphviz Entities with circular relationships (e.g., UserProfileUser) may cause infinite loops. Mitigate with:

    $graphvizLogger = new GraphvizLogger(['ignoreCircularReferences' => true]);
    

Debugging Tips

  1. Verify Doctrine Events Ensure events are dispatched correctly by adding a debug listener:

    use Doctrine\ORM\Event\OnFlushEventArgs;
    
    $eventManager->addEventListener(Events::onFlush, function (OnFlushEventArgs $args) {
        \Log::debug('Doctrine flush event triggered', ['entities' => $args->getEntityChanges()]);
    });
    
  2. Check Monolog Configuration Validate Monolog channels and handlers:

    $monolog = app('monolog');
    \Log::debug('Monolog channels:', ['channels' => $monolog->getChannels()]);
    
  3. Inspect Entity Metadata Debug metadata issues:

    $metadata = $entityManager->getClassMetadata(User::class);
    \Log::debug('Entity metadata:', [
        'name' => $metadata->name,
        'mappedSuperclass' => $metadata->isMappedSuperclass(),
    ]);
    
  4. Log Query Timings Use QueryLogger to identify slow queries:

    $logger = new QueryLogger($entityManager, $monologLogger);
    $logger->logQueryTime('SELECT * FROM users', 150); // Log a query taking 150ms
    

Extension Points

  1. Custom Log Formatters Extend DoctrineExtraLogger to format logs for specific needs:

    class CustomDoctrineLogger extends DoctrineExtraLogger
    {
        protected function formatEntityLog(array $data): string
        {
            return json_encode([
                'entity' => $data['entity'],
                'event' => $data['event'],
                'timestamp' => now()->toIso8601String(),
            ]);
        }
    }
    
  2. Add Custom Event Listeners Extend the logger to handle custom Doctrine events:

    use Doctrine\ORM\Event\PostGenerateEntityIdEventArgs;
    
    $eventManager->addEventListener(Events::postGenerateEntityId, function (PostGenerateEntityIdEventArgs $args) {
        $logger = new DoctrineExtraLogger($args->getEntityManager(), $monologLogger);
        $logger->logEvent('postGenerateEntityId', $args->getEntity());
    });
    
  3. Integrate with Laravel Logging Bridge Doctrine logs to Laravel's Log facade:

    use Draw\DoctrineExtra\Logger\DoctrineExtraLogger;
    
    $logger = new DoctrineExtraLogger($entityManager, new MonologLoggerAdapter());
    $logger->logQuery('SELECT * FROM users');
    
    // MonologLoggerAdapter.php
    class MonologLoggerAdapter
    {
        public function log($level, string $message, array $context = []): void
        {
            \Log::channel('doctrine')->$level($message, $context);
        }
    }
    
  4. Visualization Enhancements Customize Graphviz output for specific use cases:

    $graphvizLogger = new GraphvizLogger([
        'attributes' => [
            'graph' => ['rankdir' => 'LR'], // Left-to-right
    
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.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime