Symfony2 - How to dynamically get Doctrine Entity Manager object

We are building a framework for building CMS and websites with many different vendor and customer sites, so there are many different types of content objects that are edited by generic controllers and helper services that do not need to (easily) know what the object manager is for a given object.

NOTE. We have multiple entity managers to share access to different databases, for example. Global, Billing, Local, etc.

There are many cases where we need to define what the EntityManager is. For example, we have a MediaHelper that dynamically associates media from the database with the corresponding fields in an entity (this does not work with associations, because Media must connect to literally any entity, and you cannot have such a dynamic association and we do not want hundreds of different associations).

The environment is in a package managed by the "Local" EntityManager. But the object can be in the global EntityManager (you cannot read it in the same entity manager). Therefore, we need to discover and store the correct object manager for the correct entity.

So how do you recommend dynamically discovering the entityManager for an entity?

Original custom method

NOTE: The accepted answer is a much better solution. It's just for archival purposes.

Here's a simple solution that works. But I don't know enough about the Symphony and Doctrine to find out, bad idea? Does anyone else know? If not, I don't know why it wouldn't be in the core, like the Doctrine utility.

I created an EntityHelper service that injects a Doctrine service into it:

gutensite_cms.entity_helper:
    class: Gutensite\CmsBundle\Service\EntityHelper
    arguments:
        - "@doctrine"

      

Then there is one simple function in the object helper to get the Entity Manager for the object (config.yml already registers packages for the entity managers):

/**
 * Automagically find the entityManager for an entity. 
 * @param $entity
 * @return mixed
 */
public function getManagerForEntity($entity) {
    $className = \Doctrine\Common\Util\ClassUtils::getRealClass(get_class($entity));
    foreach (array_keys($this->doctrine->getManagers()) as $name) {
        if(in_array($className, $this->doctrine->getManager($name)->getConfiguration()->getMetadataDriverImpl()->getAllClassNames())) return $em;
    }
}

      

NOTE: Doctrine Registry # getAliasNamespace is already doing something almost identical to this foreach loop, I just changed the idea to return the entity manager instead of the namespace like

public function getAliasNamespace($alias) {
    foreach (array_keys($this->getManagers()) as $name) {
        try {
            return $this->getManager($name)->getConfiguration()->getEntityNamespace($alias);
        } catch (ORMException $e) {
        }
    }
    throw ORMException::unknownEntityNamespace($alias);
}

      

Update 10/21/15: Entity detection code updated as requested by @Cerad.

+2


source to share


2 answers


As suggested by @qooplmao, there is a simple method in Doctrine core.

// 1) get the real class for the entity with the Doctrine Utility.
$class = \Doctrine\Common\Util\ClassUtils::getRealClass(get_class($entity))

// 2) get the manager for that class. 
$entityManager = $this->container->get('doctrine')->getManagerForClass($class);

      



Updated 10/22/15 Following suggestions from Cerad and Qooplmao

+1


source


Can't you provide the entity manager with an alias that's appropriate for the context? You are talking about global, billing, local, like for example:

'service_manager' => array(
    'aliases' => array(
        'global_entity_manager' => 'My\Global\EntityManager',
        'billing_entity_manager' => 'My\Billing\EntityManager', 
        'local_entity_manager' => 'My\Local\EntityManager',
    ),
)

      




You can also map the Object Manager to the Object Namespace. So, let's say you have a folder for your global entities, which Global\Entity

then you can pseudonize the object manager for those objects Global\Entity\EntityManager

. The advantage of this solution is that you can map multiple namespaces to the same entity manager, so your entities Billing

and Global

can easily use the same entity manager:

'service_manager' => array(
    'aliases' => array(
        'Global\Entity\EntityManager' => 'My\Global\EntityManager',
        'Billing\Entity\EntityManager' => 'My\Global\EntityManager', // <-same name
        'Local\Entity\EntityManager' => 'My\Local\EntityManager',
    ),
)

      

This only works if your entities in the same namespace are managers of the same instance EntityManager

. I can hardly believe that this is not the case in any project, but otherwise you have to rebuild a little?: D

0


source







All Articles