Настройка кеша Redis и memcached для Zend Framework 2 и Doctrine 2

zend cache doctrine

До сих пор я использовал кеш . Однако в виду больших возможностей с Redis и лучшей экосистемы и на волне его популярности я решил перейти на него.
В интернете крайне мало материалов по настройке кеша для и 2. Если и есть материалы, то они не полные или не корректные. Поэтмоу я решил собрать свой опыт в этой статье.

Для начала надо сконфигурировать кеш для 2. Тут есть 2 пути. Первый это создание своей фабрики для наполнения \Zend\\Storage\Adapter\Redis конфигурацией через метод getOptions() и далее вызовов методов сеттеров, например setTtl(). Но я считаю этот метод избыточным в виду того, что есть другой путь – опеределить настройки через конфиг.
Для этого надо создать файл config/autoload/cache.local.php

Тут сконфигурирован кеш через memcached и redis адаптеры. Для проверки настроек и примера использования прямо в контроллере написан такой код.

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

Теперь надо настроить redis и memcached для Doctrine.
Для этого нужны будут фабрики. В принципе я не рекомендовал бы использовать анонимные ф-ии в конфигах, т.к. тогда не работает кеш конфигов Zend2, выдается ошибка с Closure.
Создать фабрики можно двумя способами. Способ первый:

Аналогично для Redis

Далее в файле cache.local.php я регистрирую эти фабрики. В этом файле, чтобы настройки кеша были в одном месте.

Почему фабрики называются именно так – станет понятно из конфигурации для Doctrine. Мой файл doctrine.local.php выглядит так

Тут кроме настройки подключения и настройки миграций добавлены настройки кеша. Указывается для Doctrine какие использовать фабрики для создания экземпляра кеша.
И выбирается конкретный экземпляр с помощью которого кешировать. Metadata Сache кеширут данные разметки (маппинга) полученные с аннотаций или с других источников (YAML, XML).
Query Cache кеширует преобразования в DQL. И наконец-то Result Cache ничего не кеширует, а только лишь устанавливает драйвер. Чтобы выполнять кеширование Result Cache, как следует из документации Doctrine и ответов на stackoverflow – это надо делать в ручную.

Как же использовать Result Cache? Вот пример для контроллера:

В этом коде получается драйвер (установленный ранее в конфиге) и используется для кеша на 200 секунд.
Но использовать Result Cache в контроллере не лучшее решение, лучше всего этот кеш вызывать в репозитории. В свой базовый класс репозитория я добавил метод, который можно вызывать вместо $query->getResult(), если нужно кешировать результат.

Вот и все, теперь настроены кеши для Zend2 и и этим можно пользоваться. Но в данном конфиге есть некоторые проблемы. Во первых не централизованы настройки кеша.
Во вторых сейчас не определено время жизни по умолчанию для Doctrine кеша. Из-за этого мы имеем бесконечный кеш метаданных в redis.
Чтобы Doctrine конфиг кеша пользовался конфигом кеша Zend имеется класс \DoctrineModule\Cache\ZendStorageCache. Для его использования фабрики кеша меняются на такие

В этих новых фабриках берется инстанс кеша Zend, например \Zend\Cache\Storage\Adapter\Redis, и на его основе испольуется кеш для Doctrine.
Почему я указал другой класс AppModel\Doctrine\Cache\ZendStorageCache? Дело в том, что в оригинальном классе \DoctrineModule\Cache\ZendStorageCache в последней версии DoctrineModule 0.8 присутствует баг, из-за которого не устанавливается время жизни при вызове метода $cache->save($cacheItemKey, $items, 200); а берется всегда из настроек.
Исследовав код я нашел причину и исправил этот баг и отправил pull request в DoctrineModule и надеюсь это будет испралвено в 0.9 версии.
Но пока что я решил проблему переопределением.

После замены кода фабрик кеш продолжает работать точно так же, как и раньше, но теперь использует настройки из файла cache.local.php. По умолчанию, если не указано время жизни, кеш будет писаться на время указанное в настройках (у меня это 7200 секунд).

UPD: 02.03.2015

Сегодня я обновил мой пулл реквест в связи с тем, что все таки логика работы класса в итоге несколько отличается от той, что я описал.
Дело в том, что в установленной для абстрактного класса ZendStorege сигнатуре метода doSave() параметр $lifeTime идет по умолчанию с 0.
Поэтому все таки по умолчанию кеш записывается со знаением 0, т.е. без истечения срока.
Это во первых. Во вторых я искал способ использовать сконфигурированное в конфиге кеша Zend значение ttl. В итоге я изменил решение на следующее.

Логику работы можно понять из комментария и из моего пояснения к pull request. https://github.com/doctrine/DoctrineModule/pull/485

UPD:

Для GUI Redis я использую следующий проект – https://github.com/ErikDubbelboer/phpRedisAdmin. Он очень похож на phpMyAdmin по стилю и функционалу и очень просто ставится.

Для Memcached раньше я использовал это https://github.com/hgschmie/phpmemcacheadmin, но там отсутствует (или не просто настраиваем) механизм авторизации, и я перешел на следующее рашение – https://github.com/clickalicious/phpMemAdmin