Symfony2, Doctrine2, Postgresql и кодировки

15 Jun 2015

Суть проблемы: в doctrine2 нет возможности выбрать кодировку подключения для драйвера pdo_pgsql. Совсем никак. Нет. Даже не пытайтесь. У вас ничего не получится.

Вот незадача: в mysql есть опция драйвера pdo PDO::MYSQL_ATTR_INIT_COMMAND. Благодаря этой опции можно устанавливать кодировку подключения при помощи

set names 'utf8'

И даже драйвер mysql поддерживает установку кодировки при помощи опции charset в настройках подключения.

Если мы покопаемся в файле драйвера, то увидим, что кодировка исправно обрабатывается

\<b\>Doctrine\DBAL\Driver\PDOMySql\Driver\</b\>

/\*\*  
 \* Constructs the MySql PDO DSN.  
 \*  
 \* @param array $params  
 \*  
 \* @return string The DSN.  
 \*/  
 private function \_constructPdoDsn(array $params)  
 {  
 $dsn = 'mysql:';  
 if (isset($params['host']) && $params['host'] != '') {  
 $dsn .= 'host=' . $params['host'] . ';';  
 }  
 if (isset($params['port'])) {  
 $dsn .= 'port=' . $params['port'] . ';';  
 }  
 if (isset($params['dbname'])) {  
 $dsn .= 'dbname=' . $params['dbname'] . ';';  
 }  
 if (isset($params['unix\_socket'])) {  
 $dsn .= 'unix\_socket=' . $params['unix\_socket'] . ';';  
 }  
 if (isset($params['charset'])) {  
 $dsn .= 'charset=' . $params['charset'] . ';';  
 }

return $dsn;  
 }

Для драйвера pdo_pgsql (Doctrine\DBAL\Driver\PDOPgSql\Driver) нет ничего подобного.

При этом сам драйвер вполне успешно с кодировками работает.

Однако, безвыходных ситуаций не бывает. Чтобы как-то изменить кодировку при работе с базой pgsql можно применять события symfony2. А конкретно событие postConnect из doctrine2.

Все, что нам потребуется - это реализовать собственный листенер этого события.

namespace DatabaseBundle\Event\Listeners;

use Doctrine\DBAL\Event\ConnectionEventArgs;  
use Doctrine\DBAL\Events;  
use Doctrine\Common\EventSubscriber;

/\*\*  
 \* Событие инициализации подключения pgsql.  
 \* Позволяет установить кодировку бд.  
 \*/  
class PgsqlConnectionInit implements EventSubscriber  
{  
 /\*\*  
 \* Используемая кодировка  
 \*  
 \* @var string  
 \*/  
 private $\_charset;

/\*\*  
 \* Конфигурирование кодировки при создании класса  
 \*  
 \* @param string $charset The charset.  
 \*/  
 public function \_\_construct($charset = 'utf8')  
 {  
 $this-\>\_charset = $charset;  
 }

/\*\*  
 \* @param \Doctrine\DBAL\Event\ConnectionEventArgs $args  
 \*  
 \* @return void  
 \*/  
 public function postConnect(ConnectionEventArgs $args)  
 {  
 $args-\>getConnection()-\>executeQuery("SET NAMES ?", array($this-\>\_charset));  
 }

/\*\*  
 \* {@inheritdoc}  
 \*/  
 public function getSubscribedEvents()  
 {  
 return array(Events::postConnect);  
 }  
}


А затем подключить этот эвент в config.yml

services:  
 pgsql.connection.init:  
 class: DatabaseBundle\Event\Listeners\PgsqlConnectionInit  
 tags:  
 - { name: doctrine.event\_listener, event: postConnect }

Теперь все ок :)