Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Multiple entity managers from the controller #176

Closed
jamiehannaford opened this Issue Feb 15, 2013 · 8 comments

Comments

Projects
None yet
4 participants

I'm using a multiple database application with Doctrine 2 and the only way I think things can work (correct me if I'm wrong) is to use multiple entity managers - one for each database.

To set these entity managers, I'm using this in my Module.php:

public function getServiceConfig()
{
    return array(
        'factories' => array(
            "doctrine.connection.users"     => new \DoctrineORMModule\Service\DBALConnectionFactory('users'),
            "doctrine.entitymanager.users"  => new \DoctrineORMModule\Service\EntityManagerFactory('users')
        )
    );
}

Then, in my config.module.php, there's a 'doctrine' key in the array with connection parameters. This allows me to access the entity manager directly in the controller:

public function getEntityManager()
{
    if (null === $this->entityManager) {
        $this->entityManager = $this->getServiceLocator()->get('doctrine.entitymanager.users');
    }

    return $this->entityManager;
} 

My question is this: how can I dynamically add entity managers for an application which will need to access dozens, maybe even hundreds, of separate databases? I've tried manually creating entity managers from the controller but everything has failed because there's no clear documentation online - everything relies on these config arrays.

Owner

Ocramius commented Feb 15, 2013

Consider defining your own abstract service factory that does pattern matching on something.your_namespace.* to handle that... I don't think DoctrineORMModule can handle that for you in a smart way right now...

I'm not quite sure how that would achieve the dynamic functionality I'm after - what do you mean by pattern matching? For classes? Config files?

Even if it did add a new entity manager, how would it initiate the correct database connection parameters? Would it still rely on the array in module.config.php?

Owner

Ocramius commented Feb 15, 2013

You would basically match a service name like your_name.eventmanager.some_name as being an eventmanager service named some_name (so pattern matching on requested service names).

Since your "hundreds" of databases is a problem when it comes to configuration (that's not really maintainable) you will need to programmatically build the factories that give you the entity manager/connection/etc.

I think I've figured out how to do it. I'm using this in a controller method:

    $sl = $this->getServiceLocator();

    $dbOptions = array(
        'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
        'params' => array(
            'host'     => 'xxx',
            'port'     => '3306',
            'user'     => 'xxx',
            'password' => 'xxx',
            'dbname'   => 'xxx',
        )
    );

    $dbOptionsClass = new \DoctrineORMModule\Options\DBALConnection($dbOptions);

    $pdo = $dbOptionsClass->getPdo();
    if (is_string($pdo)) {
        $pdo = $sl->get($pdo);
    }

    $params = array(
        'driverClass'  => $dbOptionsClass->getDriverClass(),
        'wrapperClass' => $dbOptionsClass->getWrapperClass(),
        'pdo'          => $pdo,
    );
    $params = array_merge($params, $dbOptionsClass->getParams());

    $dbConfig = $sl->get($dbOptionsClass->getConfiguration());
    $dbEventManager = $sl->get($dbOptionsClass->getEventManager());
    $conn = \Doctrine\DBAL\DriverManager::getConnection($params, $dbConfig, $eventManager);

    $emOptions = array();
    $emOptionsClass = new \DoctrineORMModule\Options\EntityManager($emOptions);
    $emConfig = $sl->get($emOptionsClass->getConfiguration());  
    $em = \Doctrine\ORM\EntityManager::create($conn, $emConfig);

And it returns the required EntityManager. This allows you to define your own EMs on-the-fly, allowing for more dynamic DB functionality (instead of relying on high-level config arrays which, as you've already pointed out, is unmaintainable). We operate a CMS, so naturally we have a lot of data flow between different schemas.

Ocramius: Does anything look critically wrong with this approach?

Owner

Ocramius commented Feb 18, 2013

@jamie-supadu no, looks good. I'm trying to abstract it away in doctrine/DoctrineModule#76 btw

@Ocramius yeah, I see. Well, even a new method in EntityManagerFactory would do. At the moment, the createService method pulls in connection parameters (etc.) from the config array via AbstractFactory and ServiceLocator. All I wanted to do is bypass this process and pass in my own array. This technically might be a bad idea because it completely goes against the Service Locator design pattern and inversion of control

Owner

Ocramius commented Feb 18, 2013

@jamie-supadu as long as it satisfies your use case and isn't about writing re-usable modules you are fine

Contributor

fabiocarneiro commented Mar 10, 2013

@jamie-supadu : there was an error in line $conn = \Doctrine\DBAL\DriverManager::getConnection($params, $dbConfig, $eventManager);

the last variable should be $dbEventManager.

@oprokidnev oprokidnev pushed a commit to oprokidnev/DoctrineORMModule that referenced this issue Apr 19, 2016

@danizord danizord Fix #176: Add zend-config dependency 32f3a47

@oprokidnev oprokidnev pushed a commit to oprokidnev/DoctrineORMModule that referenced this issue Apr 19, 2016

@Ocramius Ocramius Merge pull request #177 from Danizord/hotfix/176
[#176] Add zend-config dependency
5224fac

@oprokidnev oprokidnev pushed a commit to oprokidnev/DoctrineORMModule that referenced this issue Apr 19, 2016

@danizord @Ocramius danizord + Ocramius Revert PR #177 - Now Zend\Mvc requires zend-config
Fix #176
a3052a6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment