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

Persistence Laravel Package

doctrine/persistence

Doctrine Persistence provides shared interfaces and abstractions for object mapper persistence in PHP. It standardizes common concepts like object managers, repositories, and metadata across Doctrine and other mappers, helping libraries integrate consistently.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

To leverage doctrine/persistence in Laravel, start by installing the package via Composer:

composer require doctrine/persistence

First Use Case: Basic Object Persistence

Laravel developers typically use Doctrine ORM (which depends on this package). For standalone use, initialize a ManagerRegistry and ObjectManager:

use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\ObjectManager;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;

// Configure a simple mapping driver (e.g., for annotations)
$metadataDriver = new AnnotationDriver(new \Doctrine\Common\Annotations\AnnotationReader(), ['path/to/entities']);

// Create a registry and manager
$registry = new ManagerRegistry();
$manager = $registry->getManager();
$manager->setMetadataDriverImpl($metadataDriver);

Key Entry Points

  • ManagerRegistry: Central registry for all ObjectManager instances.
  • ObjectManager: Core interface for persisting entities (CRUD operations).
  • MappingDriverChain: Combines multiple mapping drivers (e.g., XML, YAML, annotations).

Implementation Patterns

1. Entity Mapping and Metadata

Define entities with Doctrine annotations/attributes and configure metadata drivers:

// Example: Using attributes (Doctrine 3.0+)
#[ORM\Entity(repositoryClass: UserRepository::class)]
class User {
    #[ORM\Id, ORM\GeneratedValue]
    private ?int $id = null;

    #[ORM\Column]
    private string $name;
}

// Configure metadata driver in Laravel's service provider
$container->singleton(ManagerRegistry::class, function ($container) {
    $registry = new ManagerRegistry();
    $driver = new AttributeDriver(new ClassLocator());
    $registry->setManager($container->make(ObjectManager::class), 'default');
    $registry->getManager('default')->setMetadataDriverImpl($driver);
    return $registry;
});

2. Repository Pattern

Extend Doctrine\Persistence\Repository\Repository for custom queries:

use Doctrine\Persistence\Repository\Repository;

class UserRepository extends Repository {
    public function findByName(string $name): array {
        return $this->createQueryBuilder('u')
            ->where('u.name = :name')
            ->setParameter('name', $name)
            ->getQuery()
            ->getResult();
    }
}

3. Event Listeners/Subscribers

Attach listeners to lifecycle events (e.g., prePersist):

use Doctrine\Persistence\Event\LifecycleEventArgs;

class UserListener {
    public function prePersist(User $user, LifecycleEventArgs $args): void {
        if (empty($user->getCreatedAt())) {
            $user->setCreatedAt(new \DateTime());
        }
    }
}

// Register in Laravel's service provider
$registry->getManager('default')->getEventManager()->addEventListener(
    ['prePersist'],
    $container->make(UserListener::class)
);

4. Transaction Management

Use ObjectManager for transactions:

$manager = $registry->getManager();
$manager->beginTransaction();
try {
    $user = new User();
    $user->setName('John Doe');
    $manager->persist($user);
    $manager->flush();
    $manager->commit();
} catch (\Exception $e) {
    $manager->rollback();
    throw $e;
}

5. QueryBuilder Integration

Leverage QueryBuilder for complex queries:

$qb = $manager->createQueryBuilder();
$qb->select('u')
   ->from(User::class, 'u')
   ->where('u.active = :active')
   ->setParameter('active', true);

$users = $qb->getQuery()->getResult();

Gotchas and Tips

1. Common Pitfalls

  • Metadata Driver Conflicts: Ensure your MappingDriverChain is configured correctly. Mixing drivers (e.g., annotations + XML) may cause conflicts.

    // Bad: Duplicate drivers
    $driverChain = new MappingDriverChain([$annotationDriver, $xmlDriver]);
    

    Fix: Use MappingDriverChain::addDriver() carefully or replace existing drivers.

  • Proxy Generation: Doctrine proxies require __toString() and other magic methods. If using enums or custom classes, ensure they implement required interfaces. Tip: Use #[ORM\Proxy] or extend Doctrine\ORM\Mapping\ClassMetadata.

  • Transaction Isolation: Laravel’s database transactions may conflict with Doctrine’s. Use DB::transaction() or Doctrine’s beginTransaction() explicitly.

2. Debugging Tips

  • Enable SQL Logging:

    $manager->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
    
  • Metadata Validation:

    php artisan doctrine:metadata:info
    

    (Requires doctrine/orm for full CLI support.)

  • Event Debugging: Use EventManager::addEventSubscriber() with a subscriber that logs events:

    $eventManager->addEventSubscriber(new class {
        public function getSubscribedEvents(): array {
            return ['onFlush', 'preUpdate'];
        }
        public function onFlush(OnFlushEventArgs $args) {
            \Log::debug('Flush event triggered');
        }
    });
    

3. Performance Quirks

  • Lazy Loading: Avoid N+1 queries by using fetch="EAGER" or join in QueryBuilder.
    $qb->addSelect('u.posts')->leftJoin('u.posts', 'p');
    
  • Caching Metadata: Enable metadata caching in production:
    $cache = new \Doctrine\Common\Cache\FilesystemCache('/path/to/cache');
    $driver = new AnnotationDriver($reader, $cache);
    

4. Extension Points

  • Custom Mapping Drivers: Implement Doctrine\Persistence\Mapping\Driver\MappingDriverInterface for custom formats (e.g., JSON).
  • Event Subscribers: Override getSubscribedEvents() to hook into Doctrine’s lifecycle.
  • Proxy Customization: Extend Doctrine\ORM\Proxy\Proxy for custom proxy behavior.

5. Laravel-Specific Tips

  • Service Container Integration: Bind ManagerRegistry and ObjectManager as singletons in Laravel’s AppServiceProvider:
    $this->app->singleton(ManagerRegistry::class, function ($app) {
        $registry = new ManagerRegistry();
        $registry->setManager($app->make(ObjectManager::class), 'default');
        return $registry;
    });
    
  • Migrations: Use doctrine/orm for migrations, but ensure doctrine/persistence is compatible with your Doctrine version.
  • Testing: Use Doctrine\Persistence\ObjectManager in tests with an in-memory database:
    $manager = new ObjectManager();
    $manager->setConnection($this->createTestConnection());
    

6. Deprecation Notes

  • Static Reflection Service: Removed in v4.0.0; use ReflectionClass or ReflectionProperty directly.
  • Doctrine Common Proxies: No longer supported; migrate to Doctrine ORM’s proxy system.
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.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai