Я использую доктрину2 с ZF2, некоторые мои библиотеки работают с Zend\Db\Adapter\Adapter, другие - с доктриной2. Теперь они подключаются к базе данных дважды. Можно ли использовать одно соединение db в доктрине и стандартном адаптере db ZF2?
zf2 доктрина2 и Zend\Db\Adapter\Adapter, использующие одно соединение с базой данных
Ответы:
Модуль DoctrineORM
принимает ресурс PDO
или имя службы, где экземпляр может быть расположен в диспетчере служб вместо обычных параметров соединения.
Первый шаг — создать фабрику сервисов, которая извлекает ресурс PDO из сервиса Zend\Db\Adapter\Adapter
.
<?php
namespace Application\Db\Service;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\Exception\ServiceNotCreatedException;
class PdoResourceFactory implements FactoryInterface
{
/**
* @param ServiceLocatorInterface $serviceLocator
* @return \PDO resource
*/
public function createService(ServiceLocatorInterface $services)
{
$dbAdapter = $services->get('Zend\Db\Adapter\Adapter');
$pdo = $dbAdapter->getDriver()->getConnection()->getResource();
if (!$pdo instanceof \PDO) {
throw new ServiceNotCreatedException('Connection resource must be an instance of PDO');
}
return $pdo;
}
}
После того, как у вас есть фабрика, достаточно просто добавить ее в диспетчер служб, настроить параметры базы данных для Zend\Db\Adapter\Adapter
и указать доктрине использовать существующий PdoResource
из диспетчера служб для подключения.
Предполагая, что вы сделали все это в одном файле, скажем, dbconn.local.php
...
<?php
return array (
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
// include the pdo resource factory
'PdoResource' => 'Application\Db\Service\PdoResourceFactory',
),
),
// db adapter config
'db' => array(
'driver' => 'pdo',
'dsn' => 'mysql:dbname=database;host=127.0.0.1',
'username' => 'username',
'password' => 'password',
),
'doctrine' => array (
'connection' => array (
'orm_default' => array (
'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
// use the resource from the zend adapter
'pdo' => 'PdoResource',
),
),
),
);
Извините за публикацию этого ответа как нового, но я не могу добавить комментарий к ответу Криспа, так как моя репутация слишком низкая, потому что я зарегистрировался в stackoverflow только для написания этого комментария:
В dbconn.local.php
, опубликованном Crisp, обязательно установите dbname
на null
, как в следующем фрагменте:
Дополнение к ответу Криспа:
<?php
return array(
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
// the lazy way of Crisp's PdoResourceFactory:
'PdoResource' => function (ServiceLocatorInterface $services) {
$dbAdapter = $services->get('Zend\Db\Adapter\Adapter');
$pdo = $dbAdapter->getDriver()->getConnection()->getResource();
if (!$pdo instanceof \PDO) {
throw new ServiceNotCreatedException('Connection resource must be an instance of PDO');
}
return $pdo;
},
),
),
// db adapter config
'db' => array(
'driver' => 'pdo',
'dsn' => 'mysql:dbname=database;host=127.0.0.1',
'username' => 'username',
'password' => 'password',
),
'doctrine' => array (
'connection' => array (
'orm_default' => array (
'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
// use the resource from the zend adapter
'pdo' => 'PdoResource',
// important addition to Crisp's answer:
'params' => array(
'dbname' => null,
),
),
),
),
);
А теперь вот почему это важно:
При звонке
$em->getConnection()->getDatabase();
на вашем EntityManager
без установки dbname
на null
вы получите "database"
в качестве имени вашей базы данных, потому что это значение по умолчанию, которое устанавливается module.config.php
из DoctrineORMModule
, как вы можете видеть здесь. Установка dbname
на null
приведет к тому, что ваш Doctrine\DBAL\Driver\PDOMySql\Driver
, который расширяет Doctrine\DBAL\Driver\AbstractMySQLDriver
, загрузит имя базы данных через SELECT DATABASE()
из самой базы данных, как вы можете видеть здесь.
Кроме того, если не установить для dbname
значение null
(или правильное имя базы данных), функция schemaInSyncWithMetadata()
Doctrine\ORM\Tools\SchemaValidator
всегда будет возвращать false, поскольку она не может загрузить текущую настройку базы данных, поскольку использует Doctrine\ORM\Tools\SchemaTool
, который использует EntityManager
Connection
, который считает, что база данных используется называется "database"
.
Так что я надеюсь, что кто-то может использовать эту информацию, чтобы сэкономить время. Я потратил полдня, чтобы понять это.
И еще раз большое спасибо Криспу за его ответ, который сэкономил мне много времени.