Хобрук: Ваш путь к мастерству в программировании

zf2 доктрина2 и Zend\Db\Adapter\Adapter, использующие одно соединение с базой данных

Я использую доктрину2 с ZF2, некоторые мои библиотеки работают с Zend\Db\Adapter\Adapter, другие - с доктриной2. Теперь они подключаются к базе данных дважды. Можно ли использовать одно соединение db в доктрине и стандартном адаптере db ZF2?


Ответы:


1

Модуль 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',
            ),
        ),
    ),
);
12.01.2014
  • Это гениально, не уверен, почему это еще не было принято. 02.10.2014
  • Спасибо, это помогло мне. 01.03.2016

  • 2

    Извините за публикацию этого ответа как нового, но я не могу добавить комментарий к ответу Криспа, так как моя репутация слишком низкая, потому что я зарегистрировался в 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".

    Так что я надеюсь, что кто-то может использовать эту информацию, чтобы сэкономить время. Я потратил полдня, чтобы понять это.

    И еще раз большое спасибо Криспу за его ответ, который сэкономил мне много времени.

    17.05.2016
    Новые материалы

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

    Внедрите OAuth в свои веб-приложения для повышения безопасности
    OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

    Как свинг-трейдеры могут использовать ИИ для больших выигрышей
    По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

    Как построить любой стол
    Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..