- PVSM.RU - https://www.pvsm.ru -
Сразу хочу сказать, что в Symfony и Doctrine я новичок и с подобного рода проблемой именно при использовании Symfony столкнулся впервые, но думаю, что и мой опыт может быть кому-то полезен при решении аналогичных или схожих задач.
Довелось мне не так давно выкладывать некий проект на Symfony2 на хост площадку, но, как это довольно часто бывает, на живом сервере приложение работать отказалось, и включив debug, я увидел уведомление примерно следующего плана:
Twig_Error_Runtime: An exception has been thrown during the rendering of a template
(«Warning: htmlspecialchars() [function.htmlspecialchars]: Invalid multibyte sequence in argument in
/.../app/cache/prod/classes.php line ...») in "..." at line ...
Причина этой ошибки кроется в том, что Twig по умолчанию экранирует всякий вывод, в том числе и с помощью функции htmlspecialchars(), которая в данном случае спотыкается о некую Invalid multibyte sequence. И решив, что было бы неплохо посмотреть эту самую Invalid multibyte sequence, я пропустил в шаблоне вывод соответствующих переменных через фильтр raw, примерно вот так:
{{ sometext|raw }}
Выяснилось, что кириллические текстовые данные из базы почему-то приходят в кодировке cp1251, хотя кодировка импортированной базы, таблиц и соотв. полей, из которых взяты значения была utf8. В phpMyAdmin, который был мне предоставлен хостером, на вкладке «Variables» моё внимание привлекли следующие значения параметров конфигурации mysql сервера:
init connect SET NAMES cp1251 collation database cp1251_general_ci collation servercp1251_general_ci ...
Очевидно, что причина была именно в init connect, который при соединении выполнял SET NAMES cp1251, потому все значения передавались в приложение как cp1251.
Подобного рода проблемы обычно решаются довольно просто — сразу после коннекта к базе в своём приложении выполняем запрос или группу запросов типа:
SET CHARACTER SET UTF8;
SET NAMES UTF8;
Но, как по мне, всякий лишний запрос к базе — это вообще не комильфо, да и «костыли» в коде фреймворка тоже. Поэтому поначалу я попытался решить вопрос через техподдержку.
Ребята из техподдержки хост-компании рассказали мне, что перенести базу на сервер, сконфигурированный под utf8 они не могут, т.к. все сервера у них работают с одинаковой конфигурацией на cp1251, а менять настройки сервера из-за одного проекта никто не будет, т.к.
изменения коснуться всех баз на этом сервере (я их прекрасно понимаю). Но проблему нужно было как-то решать…
Однако, решение на Symfony оказалось довольно изящным, что и послужило поводом к написанию данной статьи.
На помощь мне пришёл крохотный EventListener, который я повесил на событие postConnect.
Для его создания нужно внести в файле app/config/config.yml (если используется YAML) в разделе «services» запись вида:
services: onconnect.listener: class: DevSomeBundleEventListenerOnConnect tags: - { name: doctrine.event_listener, event: postConnect }
Теперь в нашем Bundle, нужно создать файл listener'a, который соответствует заданному в конфигурации выше namespace (DevSomeBundleEventListenerOnConnect).
т.е. Ложим в папку Dev/SomeBundle/EventListener файл OnConnect.php следующего содержания:
<?php
//file src/Dev/SomeBundle/EventListener/OnConnect.php
namespace DevSomeBundleEventListener;
use DoctrineCommonPersistenceEventLifecycleEventArgs;
use DoctrineORMEntityManager;
class OnConnect
{
public function postConnect( $event )
{
$conn = $event->getConnection();
$conn->executeQuery("SET NAMES UTF8");
}
}
В моём случае проблема с кодровкой была полностью устранена, и к тому же, мне не пришлось вставлять какие-либо «хаки» в doctrine или код фреймворка. Механизм прослушивания событий широко применяется в Symfony для решения самых различных задач. В описанном выше примере использовался Symfony 2.2.0 (Standard Edition).
Автор: dimmask
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/mysql/31940
Ссылки в тексте:
[1] Источник: http://habrahabr.ru/post/176463/
Нажмите здесь для печати.