SqlDataProvider и кодировки

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
netscorpion
Сообщения: 35
Зарегистрирован: 2015.06.09, 16:11

SqlDataProvider и кодировки

Сообщение netscorpion »

Добрый день, прошу уважаемую публику помочь разобраться с проблемой кодировок.
Итак проблема достаточно тривиальная но как еще решить в рамках SqlDataProvider я не могу понять.
По существу есть база Oracle и настроено подключение к ней через oci

Код: Выделить всё

return [
    'dsn' => 'oci:dbname=//192.168.XXX.XXX:1521/XXXXX;charset=AMERICAN_AMERICA.CL8MSWIN1251', // Для Работы
    'username' => 'XXXXX',
    'password' => 'XXXXX',
    ];
При использовании моделей построенных Gii на базе ActiveRecord при выводе данных приходится включать для некоторых полей в модели следующий код

Код: Выделить всё

  public function afterFind()
    {
        $this->DESCRIPTION_CIRCUIT = iconv('windows-1251', 'UTF-8',$this->DESCRIPTION_CIRCUIT);
        $this->DESCRIPTION_TRN = iconv('windows-1251', 'UTF-8',$this->DESCRIPTION_TRN);
        $this->DESCRIPTION_BELONGING = iconv('windows-1251', 'UTF-8',$this->DESCRIPTION_BELONGING);
        $this->DESCRIPTION_WHENCE_TRN = iconv('windows-1251', 'UTF-8',$this->DESCRIPTION_WHENCE_TRN);
    }
Что позволяет нормально преобразовывать кодировки и отдавать данные в таблицу.

Но есть заморочка. Я сейчас ковыряюсь с Rest API и выдавать данные нужно на основании не кислого запроса объеденяющего 3 таблицы со всякими подменами и преоброзованием данных. Такой запрос строить на ActiveRecord было-бы гибельным делом, и я не долго думаю сделал его на базе SqlDataProvider.

Код: Выделить всё

public  function prepareDataProvider()
    {
	$exp_RID = new Expression('SELECT CONCAT(CONCAT(TO_CHAR(c.DATA, \'DD.MM.YYYY\'), \' \'), TO_CHAR(TO_DATE(c.VREMYA, \'SSSSS\'), 		\'HH24:MI:SS\')) AS mDATA, 
                                        c.ID_KLIENTA, 
                                        c.GR_NOMER, 
                                        --------
				 WHERE c.OPERATZIYA IN (0, 1) 
                                        AND c.NOMER_TERMINALA > 0 
                                        AND c.GR_NOMER <> 0                   
 $dataProvider = new SqlDataProvider([
                    'sql' => $exp_RID,
        ]);   
                return $dataProvider;

    }                                                           
В итоге у меня данные выдаются в формате AMERICAN_AMERICA.CL8MSWIN1251 и при обращении к контролеру Rest который все выворачивает в JSON выдается ошибка

Код: Выделить всё

{
    "name": "Exception",
    "message": "Malformed UTF-8 characters, possibly incorrectly encoded.",
    "code": 5,
    "type": "yii\\base\\InvalidParamException",
    "file": "/var/www/html/pertolrestapi/vendor/yiisoft/yii2/helpers/BaseJson.php",
    "line": 132,
    "stack-trace": [
        "#0 /var/www/html/pertolrestapi/vendor/yiisoft/yii2/helpers/BaseJson.php(66): yii\\helpers\\BaseJson::handleJsonError(5)",
        "#1 /var/www/html/pertolrestapi/vendor/yiisoft/yii2/web/JsonResponseFormatter.php(89): yii\\helpers\\BaseJson::encode(Array, 448)",
        "#2 /var/www/html/pertolrestapi/vendor/yiisoft/yii2/web/JsonResponseFormatter.php(73): yii\\web\\JsonResponseFormatter->formatJson(Object(yii\\web\\Response))",
        "#3 /var/www/html/pertolrestapi/vendor/yiisoft/yii2/web/Response.php(1009): yii\\web\\JsonResponseFormatter->format(Object(yii\\web\\Response))",
        "#4 /var/www/html/pertolrestapi/vendor/yiisoft/yii2/web/Response.php(315): yii\\web\\Response->prepare()",
        "#5 /var/www/html/pertolrestapi/vendor/yiisoft/yii2/base/Application.php(385): yii\\web\\Response->send()",
        "#6 /var/www/html/pertolrestapi/web/index.php(12): yii\\base\\Application->run()",
        "#7 {main}"
    ]
}
Как я понимаю проблема как раз в кодировках но как их преоброзовать используя SqlDataProvider я просто не понимаю.
netscorpion
Сообщения: 35
Зарегистрирован: 2015.06.09, 16:11

Re: SqlDataProvider и кодировки

Сообщение netscorpion »

Небольшое дополнение преоброзование формата производится принудительно следующим образом

Код: Выделить всё

    public function behaviors()
    {
        $behaviors = parent::behaviors();
        // Перевод данных в JSON
        $behaviors['contentNegotiator'] = [
            'class' => \yii\filters\ContentNegotiator::className(),
            'formats' => [
                'application/json' => \yii\web\Response::FORMAT_JSON,
            ],
        ];
        return $behaviors;
    }
Может кто знает как перед вызовом преоброзования конвертировать данные !?!??!?
netscorpion
Сообщения: 35
Зарегистрирован: 2015.06.09, 16:11

Re: SqlDataProvider и кодировки

Сообщение netscorpion »

Тему можно закрывать.
Все оказалась достаточно просто для решения таких проблем и преоброзования вывода данных используется класс yii\rest\Serializer http://www.yiiframework.com/doc-2.0/yii ... lizer.html. Для решения именно моей проблемы я добавил следующий код в свой контроллер

Код: Выделить всё

   public $serializer = [
        'class' => '\app\controllers\MySerializer'
    ];
Ну расширил стандартный Serializer

Код: Выделить всё

namespace app\controllers;
use yii\rest\Serializer;

class MySerializer extends Serializer
{
    public function serialize($data)
    {
        $d = parent::serialize($data);
        foreach ($d as &$row) {
            $row['DESCRIPTION_PRICHINY'] = iconv('windows-1251', 'UTF-8',$row['DESCRIPTION_PRICHINY']);
            $row['NAME_TO'] = iconv('windows-1251', 'UTF-8',$row['NAME_TO']);
            $row['ADDRESS_TO'] = iconv('windows-1251', 'UTF-8',$row['ADDRESS_TO']);
            $row['DESCRIPTION_KOSH_ZA_CHTO'] = iconv('windows-1251', 'UTF-8',$row['DESCRIPTION_KOSH_ZA_CHTO']);
        }
        return $d;
    }
}

В итоге получил отличный вывод в JSON.

Уважаемые коллеги если вы знаете более простой вариант решения то прошу огласить
Maximal
Сообщения: 2
Зарегистрирован: 2017.12.12, 17:46

Re: SqlDataProvider и кодировки

Сообщение Maximal »

Коллеги,
у меня аналогичная ситуация.

Есть ли какое-то более простое Решение?
(кроме конвертации afterFind $this->DESCRIPTION_CIRCUIT = iconv('windows-1251', 'UTF-8',$this->DESCRIPTION_CIRCUIT);)

Сайт будет работать на 2 языках Русском и Английском.
Могу я перкодировать русские файлы фреймворка в 1251 ?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: SqlDataProvider и кодировки

Сообщение zelenin »

Maximal писал(а): 2017.12.12, 17:55 Коллеги,
у меня аналогичная ситуация.

Есть ли какое-то более простое Решение?
(кроме конвертации afterFind $this->DESCRIPTION_CIRCUIT = iconv('windows-1251', 'UTF-8',$this->DESCRIPTION_CIRCUIT);)

Сайт будет работать на 2 языках Русском и Английском.
Могу я перкодировать русские файлы фреймворка в 1251 ?
а юзать везде utf-8 не вариант? нужно поддерживать какие-то сторонние клиенты с другой кодировкой? откуда взялось 1251?
Maximal
Сообщения: 2
Зарегистрирован: 2017.12.12, 17:46

Re: SqlDataProvider и кодировки

Сообщение Maximal »

1251 потому, что База Oracle на кодировке 1251.
netscorpion
Сообщения: 35
Зарегистрирован: 2015.06.09, 16:11

Re: SqlDataProvider и кодировки

Сообщение netscorpion »

Добрый день, нет ни каких проблем в таком использовании конвертации данных. На своем опыте могу сказать что дополнив модели такой конструкцией полностью решается проблемма выборки данных. На производительности это особо не отражается.
P.S. Ситуация аналогичная, база Oracle в кодировке 1251.
Ответить