I am trying to extend the EntityManager in Doctrine using the EntityManagerDecorator and have run into a problem with a reference to the base EntityManager in the UnitOfWork being passed to the prePersist event via the $eventArgs.
It looks like the EntityManager is passed to the UnitOfWork in the EntityManager::__construct when the UnitOfWork is created.
I thought a solution might be that I can override the default UnitOfWork in MyEntityManagerDecorator::getUnitOfWork() like:
public function getUnitOfWork()
{
if ($this->unitOfWork === null) {
$this->unitOfWork = new UnitOfWork($this);
}
return $this->unitOfWork;
}
However I noticed that the UnitOfWork::__construct() requires an EntityManager not an EntityManagerInterface so this would not work.
I am looking for how I can get MyEntityManagerDecorator from the prePersist $eventArgs->getEntityManager() instead of the base EntityManager. I would like to do this without directly inheriting the EntityManager. The docs also say "You should never attempt to inherit from the EntityManager: Inheritance is not a valid extension point for the EntityManager.".
I am not sure what you require for code samples, if any, so please let me know if you require more information. I have access to MyEntityManagerDecorator as expected everywhere else in the project (that I have tried so far). I setup the decorator in yml like so:
my_multi_tenant_entity_manager:
public: false
class: My\MultiTenantBundle\ORM\MyEntityManagerDecorator
decorates: doctrine.orm.default_entity_manager
arguments: [ "@my_multi_tenant_entity_manager.inner" ]
Here is a list of packages and version numbers I am using dumped from composer:
installed:
doctrine/annotations v1.2.3 Docblock Annotations Parser
doctrine/cache v1.4.0 Caching library offering...
doctrine/collections v1.2 Collections Abstraction ...
doctrine/common v2.4.2 Common Library for Doctr...
doctrine/dbal v2.5.1 Database Abstraction Layer
doctrine/doctrine-bundle v1.3.0 Symfony DoctrineBundle
doctrine/doctrine-cache-bundle v1.0.1 Symfony2 Bundle for Doct...
doctrine/doctrine-migrations-bundle dev-master 6a1bd73 Symfony DoctrineMigratio...
doctrine/inflector v1.0.1 Common String Manipulati...
doctrine/instantiator 1.0.4 A small, lightweight uti...
doctrine/lexer v1.0.1 Base library for a lexer...
doctrine/migrations dev-master 058a463 Database Schema migratio...
doctrine/orm v2.4.7 Object-Relational-Mapper...
incenteev/composer-parameter-handler v2.1.0 Composer script handling...
jdorn/sql-formatter v1.2.17 a PHP SQL highlighting l...
kriswallsmith/assetic v1.2.1 Asset Management for PHP
monolog/monolog 1.12.0 Sends your logs to files...
phpdocumentor/reflection-docblock 2.0.4
phpspec/prophecy v1.3.1 Highly opinionated mocki...
phpunit/php-code-coverage 2.0.15 Library that provides co...
phpunit/php-file-iterator 1.3.4 FilterIterator implement...
phpunit/php-text-template 1.2.0 Simple template engine.
phpunit/php-timer 1.0.5 Utility class for timing
phpunit/php-token-stream 1.4.0 Wrapper around PHP's tok...
phpunit/phpunit 4.5.0 The PHP Unit Testing fra...
phpunit/phpunit-mock-objects 2.3.0 Mock Object library for ...
psr/log 1.0.0 Common interface for log...
raven/raven dev-master 407d770 A PHP client for Sentry ...
sebastian/comparator 1.1.1 Provides the functionali...
sebastian/diff 1.2.0 Diff implementation
sebastian/environment 1.2.1 Provides functionality t...
sebastian/exporter 1.2.0 Provides the functionali...
sebastian/global-state 1.0.0 Snapshotting of global s...
sebastian/recursion-context 1.0.0 Provides functionality t...
sebastian/version 1.0.4 Library that helps with ...
sensio/distribution-bundle v3.0.16 Base bundle for Symfony ...
sensio/framework-extra-bundle v3.0.4 This bundle provides a w...
sensio/generator-bundle v2.5.2 This bundle generates co...
sensiolabs/security-checker v2.0.1 A security checker for y...
swiftmailer/swiftmailer v5.3.1 Swiftmailer, free featur...
symfony/assetic-bundle v2.6.1 Integrates Assetic into ...
symfony/monolog-bundle v2.7.1 Symfony MonologBundle
symfony/swiftmailer-bundle v2.3.8 Symfony SwiftmailerBundle
symfony/symfony v2.6.4 The Symfony PHP framework
twig/extensions v1.2.0 Common additional featur...
twig/twig v1.18.0 Twig, the flexible, fast...
I would suggest to decorate (and not directly extend) the EntityManager, as it looses the coupling between your implementation and the inherited component.
In order to be able to distinguish entities that do have a relationship to a tenant implement/extend those classes from an interface or a mapped superclass.
The securityContext (for demonstration purpose) is there to get the reference to the tenant.
/**
* `EntityManagerDecorator` exists since v2.4
*/
class MultiTenantEntityManager extends EntityManagerDecorator {
private $securityContext;
public function __construct(EntityManagerInterface $entityManager, $securityContext) {
parent::__construct($entityManager);
$this->securityContext = $securityContext;
}
public function persist($entity) {
// set the tenant before persisting an entity
if ($entity instanceof MultiTenantEntity) {
$userId = $this->securityContext->getUserId();
$tenant = $this->wrapped->find($userId,...);
$entity->setTenant($tenant);
}
return $this->wrapped->persist($entity);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With