ryakad ryakad - 1 year ago 151
PHP Question

Extending Doctrine EntityManager with EntityManagerDecorator leaves wrong reference in UnitOfWork

I am trying to extend the

in Doctrine using the
and have run into a problem with a reference to the base
in the
being passed to the
event via the

It looks like the
is passed to the
in the
when the
is created.

I thought a solution might be that I can override the default

public function getUnitOfWork()
if ($this->unitOfWork === null) {
$this->unitOfWork = new UnitOfWork($this);

return $this->unitOfWork;

However I noticed that the
requires an
not an
so this would not work.

I am looking for how I can get
from the prePersist
instead of the base
. I would like to do this without directly inheriting the
. 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
as expected everywhere else in the project (that I have tried so far). I setup the decorator in
like so:

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:

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...

Answer Source

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) {
        $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,...);
        return $this->wrapped->persist($entity);