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 Bridge Laravel Package

symfony/doctrine-bridge

Symfony Doctrine Bridge integrates Doctrine ORM and related libraries with Symfony components, providing seamless wiring for services, repositories, persistence, and tooling. Ideal for projects using Doctrine alongside Symfony’s DI container, validator, and other features.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require symfony/doctrine-bridge
    

    Ensure doctrine/orm and doctrine/doctrine-bundle are also installed for full functionality.

  2. Configuration: Add to config/packages/doctrine.yaml:

    doctrine:
        dbal:
            driver: 'pdo_mysql'
            url: '%env(DATABASE_URL)%'
        orm:
            auto_generate_proxy_classes: true
            naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
            auto_mapping: true
            mappings:
                App:
                    is_bundle: false
                    type: attribute
                    dir: '%kernel.project_dir%/src/Entity'
                    prefix: 'App\Entity'
                    alias: App
    
  3. First Use Case: Create an entity (e.g., src/Entity/User.php):

    use Doctrine\ORM\Mapping as ORM;
    
    #[ORM\Entity(repositoryClass: UserRepository::class)]
    class User
    {
        #[ORM\Id]
        #[ORM\GeneratedValue]
        #[ORM\Column]
        private ?int $id = null;
    
        #[ORM\Column(length: 180, unique: true)]
        private string $email;
    
        // Getters/setters...
    }
    

    Use in a controller:

    use Doctrine\ORM\EntityManagerInterface;
    use Symfony\Component\HttpFoundation\Response;
    
    class UserController
    {
        public function __construct(private EntityManagerInterface $em) {}
    
        public function index(): Response
        {
            $users = $this->em->getRepository(User::class)->findAll();
            return new Response(json_encode($users));
        }
    }
    
  4. Key Entry Points:

    • EntityManagerInterface (injected via dependency injection).
    • Doctrine\ORM\EntityRepository (for custom queries).
    • Symfony’s Validator (for entity validation).

Implementation Patterns

1. Dependency Injection and Services

  • Inject EntityManagerInterface into controllers/services:
    public function __construct(private EntityManagerInterface $em) {}
    
  • Use ObjectManager for non-persistent operations (e.g., hydration):
    $user = $this->em->getRepository(User::class)->find($id);
    $this->em->getObjectManager()->detach($user); // Detach for non-persistent use
    

2. Repository Patterns

  • Custom Repositories:
    #[ORM\Entity(repositoryClass: CustomUserRepository::class)]
    class User {}
    
    class CustomUserRepository extends ServiceEntityRepository
    {
        public function findActiveUsers(): array
        {
            return $this->createQueryBuilder('u')
                ->where('u.isActive = :active')
                ->setParameter('active', true)
                ->getQuery()
                ->getResult();
        }
    }
    
  • QueryBuilder for Complex Queries:
    $qb = $this->em->createQueryBuilder();
    $qb->select('u', 'p')
       ->from(User::class, 'u')
       ->join('u.posts', 'p')
       ->where('p.published = :published')
       ->setParameter('published', true);
    

3. Validation Integration

  • Entity Validation:
    use Symfony\Component\Validator\Constraints as Assert;
    
    #[ORM\Entity]
    class User
    {
        #[ORM\Column(length: 180)]
        #[Assert\Email]
        private string $email;
    }
    
  • Manual Validation:
    $errors = $validator->validate($user);
    if (count($errors) > 0) {
        // Handle errors
    }
    

4. Lifecycle Callbacks

  • Pre/Post Persist/Update:
    #[ORM\Entity]
    class Product
    {
        #[ORM\PrePersist]
        public function setCreatedAt(): void
        {
            $this->createdAt = new \DateTime();
        }
    }
    

5. Transactions

  • Explicit Transactions:
    $this->em->beginTransaction();
    try {
        $this->em->persist($user);
        $this->em->flush();
        $this->em->commit();
    } catch (\Exception $e) {
        $this->em->rollBack();
        throw $e;
    }
    
  • Doctrine Event Listeners (e.g., for auditing):
    #[AsEventListener(event: 'prePersist')]
    public function prePersist(User $user): void
    {
        $user->setCreatedAt(new \DateTime());
    }
    

6. DQL and Native Queries

  • DQL:
    $query = $this->em->createQuery('SELECT u FROM App\Entity\User u WHERE u.email LIKE :email');
    $query->setParameter('email', '%@example.com');
    $users = $query->getResult();
    
  • Native SQL:
    $sql = 'SELECT * FROM user WHERE email = ?';
    $stmt = $this->em->getConnection()->prepare($sql);
    $stmt->execute(['user@example.com']);
    $users = $stmt->fetchAllAssociative();
    

7. Symfony Forms + Doctrine

  • EntityType Field:
    $builder->add('user', EntityType::class, [
        'class' => User::class,
        'choice_label' => 'email',
    ]);
    
  • Form Events:
    $form->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
        $data = $event->getData();
        // Custom logic
    });
    

8. Caching Strategies

  • Second-Level Cache:
    # config/packages/doctrine.yaml
    orm:
        second_level_cache:
            enabled: true
            region_directory: '%kernel.cache_dir%/doctrine'
    
  • Query Cache:
    $query->setCacheable(true);
    $query->setCacheLifetime(3600);
    

9. Migrations

  • Doctrine Migrations Bundle:
    composer require doctrine/doctrine-migrations-bundle
    php bin/console doctrine:migrations:diff
    php bin/console doctrine:migrations:migrate
    

Gotchas and Tips

Common Pitfalls

  1. Lazy Loading in Serialization:

    • Issue: Serializing entities with lazy-loaded associations throws LazyInitializationException.
    • Fix: Use EntityManager::getObjectManager()->detach() or fetch associations eagerly:
      $user = $this->em->find(User::class, $id);
      $this->em->getObjectManager()->refresh($user); // Force load
      
  2. Circular References in JSON:

    • Issue: Serializing entities with bidirectional relationships causes infinite loops.
    • Fix: Use JsonSerializable or Serializer with groups:
      #[Groups(['user:read'])]
      public function getPosts(): array { return $this->posts; }
      
      $serializer->serialize($user, 'json', ['groups' => ['user:read']]);
      
  3. Transaction Boundaries:

    • Issue: Forgetting to commit transactions or handling rollbacks improperly.
    • Tip: Use try-catch blocks and ensure flush() is called only after all operations:
      $this->em->persist($entity);
      $this->em->flush(); // Only after all persists/updates
      
  4. Schema Updates:

    • Issue: Schema updates (e.g., ALTER TABLE) may fail silently or lock tables.
    • Fix: Use migrations for schema changes and avoid direct SQL in production:
      php bin/console doctrine:schema:update --force
      
  5. Entity Manager Scope:

    • Issue: Using the wrong EntityManager (e.g., from a subrequest).
    • Fix: Inject EntityManagerInterface and avoid static calls. For subrequests, use:
      $this->em->getConnection()->getWrappedConnection();
      
  6. Unique Constraints:

    • Issue: @UniqueEntity validator may not work as expected with custom repositories.
    • Fix: Ensure the repository method matches the constraint:
      #[UniqueEntity(fields: 'email', message: 'Email already taken')]
      class User {}
      
      // Repository must implement findByEmail()
      public function findByEmail(string $email): ?User { ... }
      
  7. Oracle Compatibility:

    • Issue: Schema subscriber checks may fail on Oracle.
    • Fix: Rename tables as per [#6358
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.
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
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