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.
## Getting Started
### Minimal Setup
1. **Installation**
```bash
composer require larapack/doctrine-support
Ensure doctrine/dbal and doctrine/orm are also installed (required dependencies).
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.
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.
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.
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.
Basic CRUD Use the Doctrine manager to interact with entities:
$doctrine = app(\Larapack\DoctrineSupport\DoctrineManager::class);
$user = $doctrine->getEntityManager()->find(User::class, 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();
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'
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
);
}
);
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);
}
);
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).
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()]);
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.
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;
// ...
}
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(),
];
}
}
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();
}
);
Entity Mapping Conflicts
App\Entities\User for Doctrine, App\Models\User for Eloquent) or disable Eloquent's auto-discovery for the model.AppServiceProvider does not auto-discover models in both namespaces.Enum Serialization
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
];
}
}
Transaction Handling
DB::transaction) with Doctrine transactions can cause deadlocks.$entityManager = $doctrine->getEntityManager();
$entityManager->beginTransaction();
try {
// Operations
$entityManager->commit();
} catch (\Exception $e) {
$entityManager->rollback();
How can I help you explore Laravel packages today?