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

larapack/doctrine-support

Laravel package that enhances Doctrine support in Laravel, including support for enum types. Install via Composer and (for Laravel 5.4 and below) register the DoctrineSupportServiceProvider. Use v0.1.3 for Laravel versions older than 5.4.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**
   ```bash
   composer require larapack/doctrine-support

Ensure doctrine/dbal and doctrine/orm are also installed (required dependencies).

  1. Service Provider Register the package in config/app.php under providers:

    Larapack\DoctrineSupport\DoctrineServiceProvider::class,
    

    Note for Laravel 6.0+: Ensure the service provider is registered in config/app.php before Illuminate\Database\DatabaseServiceProvider if using shared database connections.

  2. Configuration Publish the config file:

    php artisan vendor:publish --provider="Larapack\DoctrineSupport\DoctrineServiceProvider"
    

    Update config/doctrine.php with your Doctrine connection settings (e.g., default_connection). Laravel 6.0+: Verify bootstrap/app.php includes the service provider in the $providerGroups array under Illuminate\Foundation\Providers\ArtisanServiceProvider::class.

  3. First Use Case: Basic Entity Define a Doctrine entity (e.g., app/Entities/User.php):

    use Doctrine\ORM\Mapping as ORM;
    
    /** @ORM\Entity */
    class User
    {
        /** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
        private $id;
    
        /** @ORM\Column(type="string") */
        private $name;
    }
    

    Register the entity in config/doctrine.php under entity_paths.

  4. Bootstrap Doctrine In a service provider (e.g., AppServiceProvider), bootstrap Doctrine:

    public function boot()
    {
        if ($this->app->environment('local', 'testing')) {
            $this->app->make(\Larapack\DoctrineSupport\DoctrineManager::class)->bootstrap();
        }
    }
    

    Laravel 6.0+: Use environment checks to avoid bootstrapping in production unless explicitly needed.

  5. Basic CRUD Use the Doctrine manager to interact with entities:

    $doctrine = app(\Larapack\DoctrineSupport\DoctrineManager::class);
    $user = $doctrine->getEntityManager()->find(User::class, 1);
    

Implementation Patterns

Workflows

  1. Hybrid ORM Workflows Use Doctrine for complex queries (e.g., DQL, native SQL) while leveraging Eloquent for simpler operations:

    // Doctrine query
    $users = $doctrine->getEntityManager()
        ->createQuery('SELECT u FROM App\Entities\User u WHERE u.name LIKE :name')
        ->setParameter('name', '%John%')
        ->getResult();
    
    // Eloquent fallback (Laravel 6.0+)
    $eloquentUser = \App\Models\User::where('name', 'John')->first();
    
  2. Enum Support Define enums in Doctrine entities and map them to Laravel-friendly values:

    use Larapack\DoctrineSupport\Enum\Enum;
    
    /** @ORM\Column(type="string", enumType="user_role") */
    private $role;
    
    // In a separate file (e.g., UserRole.php)
    class UserRole extends Enum
    {
        const ADMIN = 'admin';
        const USER = 'user';
    
        public function label(): string
        {
            return match($this->value) {
                self::ADMIN => 'Administrator',
                self::USER => 'Regular User',
            };
        }
    }
    

    Access enum values via:

    $user->role->value(); // Returns 'admin'
    $user->role->label(); // Returns 'Administrator'
    
  3. Repository Pattern Create custom repositories for entities:

    namespace App\Repositories;
    
    use Larapack\DoctrineSupport\Repository\DoctrineRepository;
    
    class UserRepository extends DoctrineRepository
    {
        public function findByRole($role)
        {
            return $this->createQueryBuilder('u')
                ->where('u.role = :role')
                ->setParameter('role', $role)
                ->getQuery()
                ->getResult();
        }
    }
    

    Bind the repository in a service provider (Laravel 6.0+):

    $this->app->singleton(
        \App\Repositories\UserRepository::class,
        function ($app) {
            return new UserRepository(
                $app->make(\Doctrine\ORM\EntityManager::class),
                \App\Entities\User::class
            );
        }
    );
    
  4. Event Listeners Attach Doctrine event listeners (e.g., for soft deletes):

    $doctrine->getEntityManager()->getEventManager()->addEventListener(
        \Doctrine\ORM\Events::PRE_REMOVE,
        function ($event) {
            $entity = $event->getEntity();
            $entity->setDeletedAt(new \DateTime());
            $event->getEntityManager()->persist($entity);
            $event->getEntityManager()->remove($entity);
        }
    );
    
  5. Migrations Use Doctrine migrations alongside Laravel migrations:

    php artisan doctrine:migrations:diff
    php artisan doctrine:migrations:migrate
    

    Laravel 6.0+: Ensure migrations are run in the correct order (Doctrine migrations first if they create tables used by Laravel).


Integration Tips

  1. Laravel Query Builder Interop Convert Laravel collections to Doctrine collections for bulk operations:

    $users = \App\Models\User::all();
    $doctrineUsers = $doctrine->getEntityManager()->getRepository(User::class)
        ->findBy(['id' => $users->pluck('id')->toArray()]);
    
  2. Caching Enable Doctrine caching in config/doctrine.php:

    'cache' => [
        'driver' => 'apcu',
        'namespace' => 'doctrine_',
    ],
    

    Laravel 6.0+: Use cache:table for database-backed caching if APCu is unavailable.

  3. Testing Use a separate Doctrine connection for testing:

    // In phpunit.xml
    <env name="DB_DATABASE_TEST" value="doctrine_test"/>
    

    Bootstrap Doctrine in phpunit.xml:

    <env name="DOCTRINE_BOOTSTRAP" value="true"/>
    

    Laravel 6.0+: Use DatabaseMigrations trait for testing:

    use Illuminate\Foundation\Testing\DatabaseMigrations;
    
    class UserTest extends TestCase
    {
        use DatabaseMigrations;
        // ...
    }
    
  4. API Resources Transform Doctrine entities to API resources:

    use Larapack\DoctrineSupport\Transformers\DoctrineTransformer;
    
    class UserTransformer extends DoctrineTransformer
    {
        public function transform(User $user)
        {
            return [
                'id' => $user->getId(),
                'name' => $user->getName(),
                'role' => $user->getRole()->value(),
            ];
        }
    }
    
  5. Service Container Binding Bind Doctrine-specific services in a service provider (Laravel 6.0+):

    $this->app->bind(
        \Doctrine\ORM\EntityManagerInterface::class,
        function ($app) {
            return $app->make(\Larapack\DoctrineSupport\DoctrineManager::class)
                ->getEntityManager();
        }
    );
    

Gotchas and Tips

Pitfalls

  1. Entity Mapping Conflicts

    • Issue: Doctrine and Eloquent may conflict if both define the same model.
    • Fix: Use separate namespaces (e.g., App\Entities\User for Doctrine, App\Models\User for Eloquent) or disable Eloquent's auto-discovery for the model.
    • Laravel 6.0+: Ensure AppServiceProvider does not auto-discover models in both namespaces.
  2. Enum Serialization

    • Issue: Enums may not serialize/deserialize correctly in JSON APIs.
    • Fix: Override JsonSerializable or use a custom transformer:
      class UserTransformer extends DoctrineTransformer
      {
          public function transform(User $user)
          {
              return [
                  'role' => $user->getRole()->value(), // Use value() instead of raw enum
              ];
          }
      }
      
  3. Transaction Handling

    • Issue: Mixing Laravel transactions (DB::transaction) with Doctrine transactions can cause deadlocks.
    • Fix: Stick to one ORM per transaction or use explicit Doctrine transactions:
      $entityManager = $doctrine->getEntityManager();
      $entityManager->beginTransaction();
      try {
          // Operations
          $entityManager->commit();
      } catch (\Exception $e) {
          $entityManager->rollback();
      
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky