Installation:
composer require laravel-doctrine/orm
php artisan vendor:publish --tag="config" --provider="LaravelDoctrine\ORM\DoctrineServiceProvider"
config/doctrine.php for database connection settings (e.g., dbal.connection, orm.connection).Define a Doctrine Entity:
// app/Models/User.php
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: "App\Repositories\UserRepository")]
class User
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column(type: "integer")]
private ?int $id = null;
#[ORM\Column(type: "string", length: 180, unique: true)]
private string $email;
// Getters/setters...
}
First Query:
use LaravelDoctrine\ORM\Facades\EntityManager;
$user = EntityManager::getRepository(User::class)->find(1);
Replace Eloquent models with Doctrine entities and use EntityManager facade for CRUD operations. Example:
// Create
$user = new User();
$user->setEmail('test@example.com');
EntityManager::persist($user);
EntityManager::flush();
// Query
$users = EntityManager::getRepository(User::class)->findBy(['email' => 'test@example.com']);
Entity Lifecycle:
EntityManager::persist() to schedule an entity for insertion.EntityManager::remove() to mark an entity for deletion.EntityManager::flush() to synchronize changes with the database.Repositories:
LaravelDoctrine\ORM\Repository\Repository for custom logic:
namespace App\Repositories;
use App\Models\User;
use LaravelDoctrine\ORM\Repository\Repository;
class UserRepository extends Repository
{
public function findActiveUsers(): array
{
return $this->createQueryBuilder('u')
->where('u.isActive = :active')
->setParameter('active', true)
->getQuery()
->getResult();
}
}
QueryBuilder Integration:
QueryBuilder for complex queries:
$qb = EntityManager::getRepository(User::class)->createQueryBuilder('u');
$qb->join('u.roles', 'r')
->where('r.name = :role')
->setParameter('role', 'admin');
$admins = $qb->getQuery()->getResult();
Transactions:
EntityManager::getConnection()->beginTransaction();
try {
// Operations...
EntityManager::getConnection()->commit();
} catch (\Exception $e) {
EntityManager::getConnection()->rollBack();
throw $e;
}
LaravelDoctrine\Eloquent\DoctrineEloquent to bridge Eloquent models with Doctrine entities.php artisan doctrine:migrations:diff) alongside Laravel migrations for schema changes.doctrine.cache in config/doctrine.php for query result caching (e.g., apcu, redis).Lazy Loading:
fetch="EAGER" or join in queries to avoid ProxyQueryException.Entity State Management:
persist() or flush() leads to unsaved changes. Always verify state with EntityManager::isOpen() or EntityManager::getUnitOfWork()->getScheduledEntityInsertions().Case Sensitivity:
Circular References:
OneToMany + ManyToOne) require careful mappedBy/inversedBy configuration to avoid infinite loops.Transaction Isolation:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED in doctrine.event_listeners if needed.$config = EntityManager::getConfiguration();
$config->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
$uow = EntityManager::getUnitOfWork();
print_r($uow->getScheduledEntityInsertions());
php artisan doctrine:schema:validate
Custom Events:
doctrine.event_dispatcher in config:
'event_dispatcher' => [
'listeners' => [
'postPersist' => [
'App\Listeners\UserCreatedListener',
],
],
],
Custom Types:
Doctrine\DBAL\Types\Type for custom database types (e.g., JSON, enum).Hybrid Repositories:
use Illuminate\Support\Facades\DB;
use LaravelDoctrine\ORM\Facades\EntityManager;
class HybridUserRepository extends Repository
{
public function findByEmailOrRaw($email)
{
return EntityManager::getRepository(User::class)
->findBy(['email' => $email])
?? DB::table('users')->where('email', $email)->first();
}
}
DQL vs. Native SQL:
EntityManager::createNativeQuery() for complex SQL not expressible in DQL:
$query = EntityManager::createNativeQuery('SELECT * FROM users WHERE email = :email');
$query->setParameter('email', 'test@example.com');
$result = $query->getResult();
orm.connection in config/doctrine.php matches your database connection name (e.g., mysql, pgsql).orm.proxy_dir to a writable directory for generated proxy classes (e.g., storage/doctrine/proxy).yaml or xml for metadata if using annotations causes performance issues. Configure via orm.metadata_driver.How can I help you explore Laravel packages today?