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

Суть проблемы: в 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 }

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

tmux + mc + ssh

Если запустить ssh в tmux, а в нем запустить mc, то последний пожалуется, что тип терминала неизвестен и закроется. А на локальной машине не работают сочетания Shift+Fx.

Решение простое — добавить в файлы на удаленных машинах следующие опции (в локальные тоже не помешает):

~/.profile

if [ $TERM = "screen" ]; then
    export TERM=xterm-color
fi
if [ -n "$TMUX" ]; then
    export COLORTERM=rxvt
fi

~/.tmux.conf

setw -g xterm-keys on

И задеплоить это с помощью ansible.

Symfony2: cannot redeclarate class

Fatal error: include() [<a href="http://contoso.com/app/function.include">function.include</a>]: Cannot redeclare class symfony\bundle\frameworkbundle\frameworkbundle in /srv/www/contoso.com/vendor/composer/ClassLoader.php on line <i>412</i>

Да-да. Есть такая противная ошибка.

Она лечится либо отключением apc, либо установкой для него следующего набора опций

apc.include_once_override = 0
apc.canonicalize = 0
apc.stat = 0

PostgreSQL: ограничиваем время выполнения запроса

db=> set statement_timeout to 100;
SET
db=> select pg_sleep(110);
ERROR:  canceling statement due to statement timeout
db=> set statement_timeout to 0;
SET
db=> 

Первым выражением установим максимальное время выполнения запроса в миллисекундах. Вторым пойдет запрос, а третьим мы снимем ограничение на время выполнения (0 — значение по умолчанию).

Дока.

OpenSUSE и шрифты

Сравнение шрифтов. Слева шрифт без нормально настроенного рендеринга, а справа - с нормально настроенным.

Сравнение шрифтов. Слева шрифт без нормально настроенного рендеринга, а справа — с нормально настроенным.

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

Как раз на картинке видно две ситуации:

  • слева дефолтный рендеринг шрифтов «искаропки»
  • справа — допиленный рендеринг infinality (который всячески нахваливают)

Осталось его лишь настроить.

zypper ar http://download.opensuse.org/repositories/home:/nick31:/INFINALITY-ULTIMATE/openSUSE_13.2/ subpixel
zypper mr -p 98 subpixel
zypper ref && sudo zypper dup
zypper in libfreetype6 libfreetype6-32bit

К слову, репозитарий выше — это единственный рабочий репозитарий с обновляемым (с нормальной скоростью) freetype и другими плюшками.

После этого можно поставить шрифт ubuntu (он даже нормально выглядит) или cantarell.

Linux и запись вебкастов

Довольно долго искал, чем же можно нормально писать вебинары.

В итоге остановился на vokoscreen.

Vokoscreen

Из достоинств:

  • выбор объект для записи (отдельный монитор, отдельное окно, область экрана);
  • выбор источника записи звука;
  • настройка формата получаемого видео (все равно видео потребует дальнешего редактирование, но приятно);
  • простой и безглючный интерфейс.

Да. Можно и из консоли писать, но при записи неудобно задавать набор опций, которые как раз дают возможность выбирать объект для захвата.

Даже если запись изначально прошла удачно, то итоговый файл все равно мало пригоден для аплоада на ютуб или куда-нибдь еще (для разрешения 1920х1080 и 60 минутах записи объем итогового файла перевалит далеко за 2 гига).

Поэтому можно воспользоваться кодемо ffmpeg. Для меня подошли следующие опции.

ffmpeg -i input.mkv -vcodec libx264 -strict -2 -crf 20 -threads 7 -r 25 output.mp4

Где:

  • -i input.mkv — исходный файл
  • -vcodec libx264 — кодек видео x264
  • -strict -2 — этот набор опций включает поддержку эекспериментального энкодера aac
  • -crf 20 — опция энкодера, которая задает степень сжатия (в мануале — это квантование). от 0 до 51. 0 — лучшее качество картинки, а 51 — наихудшее.
  • -threads 7 — количество потоков (равно количество реально-виртуальных ядер минус один. в таком случае можно за компьютером еще что-то делать)
  • -r 25 — кадры в секунду для выходного видео
  • output.mp4 — куда пишем

Подробный мануал по кодирования x264.

JavaScript и области видимости

Об этой особенности полезно иногда вспоминать.

// глобальная переменная, которую мы попытаемся дальше получить
var bar = 42;

// Мозг предполагает, что до объявления bar в теле функциии глобальный bar будет доступен
function simple_define() {
    alert(bar);
    var bar = 10;
    alert(bar);
}

// Но это не так. Функция выше на самом деле выглядит вот так
function real_define() {
    var bar;
    alert(bar);
    bar = 10;
    alert(bar);
}

// А что же с условиями? Разве они не создают локальные области видимости?
function define_inside_if() {
    if (true) {
        var bar = -10;
    }
    
    alert(bar);
}

// Ну а циклы?
function define_inside_while() {
    do {
        var bar = 10;
    } while (false);
    alert(bar);
}

// И переменные из for?
function define_inside_for() {
    for (var bar = 0; bar < 10; bar++);
    alert(bar);
}

/* 
 * Да. Это особенность js - компилятор собирает все объявления переменных текущей области видимости
 * и выделяет под них все требуемые ресурсы сразу при входе в функцию.
 */