Laravel Doctrine ORM
repository·3.3.x·Indexed 21 days ago
https://github.com/laravel-doctrine/ormAn integration library that bridges the Laravel ecosystem with Doctrine ORM's data mapping capabilities. It provides support for multiple entity managers, custom cache drivers, and database connection management. The package includes tools for implementing Laravel's Authenticatable contract on Doctrine entities, managing database schemas via Artisan commands, and configuring metadata, query, and result caching.
What's inside laravel-doctrine-orm
- Laravel Doctrine ORM is an integration library that brings Doctrine ORM to the Laravel ecosystem. It allows you to use the Data Mapper pattern instead of the traditional Active Record pattern used by Eloquent. This provides a complete separation between your domain/business logic and the relational database persistence layer, allowing you to focus on object-oriented logic.
Supported caching systems
3.3.xThe package provides out-of-the-box support for the following caching systems:
redismemcachedfileapcarray
Manage entity relations using Collections
3.3.xWhen defining one-to-many or many-to-many relations, the property type should be
Doctrine\Common\Collections\Collection.To ensure relations are ready for use upon instantiation, you should initialize collection properties with an empty
Doctrine\Common\Collections\ArrayCollectionin the entity's constructor. This allows you to use standard collection methods immediately:->add($element): Add a new relation.->removeElement($element): Remove a relation.->contains($element): Check if a relation is already defined.
use Doctrine\ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; class Scientist { #[ORM\OneToMany(targetEntity: Theory::class, mappedBy: "scientist")] private Collection $theories; public function __construct() { $this->theories = new ArrayCollection(); } }How DoctrineManager provides advanced configuration
3.3.xThe
DoctrineManagerallows you to hook into the internals of a Doctrine Entity Manager to perform advanced configuration that cannot be achieved via the standarddoctrine.phpconfiguration file.It provides access to three core Doctrine facets for a specific Entity Manager (identified by the name configured in
doctrine.php):Doctrine\ORM\ConfigurationDoctrine\DBAL\ConnectionDoctrine\Common\EventManager
How the Identity Map Pattern works in Doctrine
3.3.xDoctrine implements the
Identity Map Pattern. This means theEntityManagerkeeps a map of all entities and their IDs retrieved during a single request. If you attempt to find the same entity multiple times, Doctrine will return the exact same instance from its internal map rather than creating a new object.Because they are the same instance, any changes made to an entity will be reflected in subsequent
findcalls for that same ID, even before the changes are flushed to the database.$entity = EntityManager::find('App\Entities\Article', 1); $entity->title = 'Different title'; // This returns the exact same instance as $entity $entityCopy = EntityManager::find('App\Entities\Article', 1); assert($entityCopy->title === 'Different title');Handle Password Hashing
3.3.xLaravelDoctrine treats passwords as plain strings. It does not handle hashing automatically. You are responsible for hashing passwords within your application logic before persisting them to the entity.
It is recommended to decouple hashing and strength validation from storage by using a dedicated service that utilizes Laravel's
\Illuminate\Contracts\Hashing\Hasher.use \Illuminate\Contracts\Hashing\Hasher; class PasswordService { private $hasher; private $passwordStrengthValidator; public function __construct( Hasher $hasher, MyPasswordStrengthValidator $passwordStrength ) { $this->hasher = $hasher; $this->passwordStrengthValidator = $passwordStrength; } public function changePassword(User $user, $password) { if ($this->passwordStrengthValidator->isStrongEnough($password)) { // Hash the password before setting it on the entity $user->setPassword($this->hasher->make($password)); } else { throw new PasswordTooWeakException(); } } }Supported database connections
3.3.xLaravel Doctrine ORM supports all database connections configured in your Laravel application's
config/database.php. This includes:mysqlsqlitepqsqlsqlsrvoci8
Read/write connection splitting is supported. Swapping the
DB_CONNECTIONenvironment variable will automatically swap the database connection used by Doctrine.Configure Namespace Aliases
3.3.xTo avoid using fully qualified class names in queries, you can define namespace aliases in your entity manager configuration. This allows you to use a short alias in DQL or when retrieving repositories.
- Define the alias as a key in the
namespacesarray. - Map the alias to the actual entity namespace.
- Use the alias in queries using the
Alias:Entityformat.
'namespaces' => [ 'Foo' => 'App\Model\Foo\Entities', 'Bar' => 'App\Model\Bar\Entities', ],Usage in SQL/DQL:
SELECT f FROM Foo:SomeEntityUsage in PHP:
EntityManager::getRepository('Bar:SomeEntity');- Define the alias as a key in the
Best practice for injecting repositories
3.3.xIt is not recommended to inject specific repository instances directly into your classes. Instead, you should inject theEntityManager. TheEntityManageracts as a container (similar to a PSR-11 container) that can provide the necessary repositories when needed. This approach keeps your dependency graph cleaner and avoids issues with repository lifecycles.Understand the Data Mapper pattern in Doctrine ORM
3.3.xUnlike Eloquent, which uses the Active Record pattern where models contain both business logic and persistence logic, Doctrine ORM uses the Data Mapper pattern.
In Doctrine, entities are plain PHP classes that represent domain objects with identity. They do not extend any base class provided by the ORM. This ensures a complete separation between your domain/business logic and the persistence logic. To bridge this gap, you must provide metadata to tell Doctrine how to map database columns to your entity properties.
Recommended Application Folder Structure
3.3.xDoctrine entities should not be placed in the standard Laravel
Modeldirectory. It is recommended to use a dedicatedapp/Doctrine/ORMdirectory.For an application with a single entity manager, the following structure is suggested:
app/Doctrine/ORM/Entityapp/Doctrine/ORM/Repositoryapp/Doctrine/ORM/Subscriberapp/Doctrine/ORM/Listener
~/app/Doctrine/ORMExtend repositories using inheritance
3.3.xYou can create a custom repository by extending Doctrine's
EntityRepository. This allows you to inherit all the standard Doctrine repository methods (likefind(),findAll(), etc.) while adding your own domain-specific methods. To use this in Laravel, you must bind your custom repository to an interface in aServiceProvider.use Doctrine\ORM\EntityRepository; // 1. Define your interface interface ScientistRepository { public function find($id); public function findByName($name); } // 2. Implement via inheritance class DoctrineScientistRepository extends EntityRepository implements ScientistRepository { public function findByName($name) { return $this->findBy(['name' => $name]); } } // 3. Bind in AppServiceProvider class AppServiceProvider { public function register() { $this->app->bind(ScientistRepository::class, function($app) { return new DoctrineScientistRepository( $app['em'], $app['em']->getClassMetaData(Scientist::class) ); }); } }