Данная статья написана в продолжении поста «ORM – зло или Как я пытался кэшировать Propel в Symfony» по наводки пользователя remal.
Как я уже писал в прошлой статье, чтобы заработал кэш необходимо переопределить 4 метода пула, которые находятся в Peer объектах:
Чтобы не дублировать код для каждого Peer объекта (по наводке пользователя remal), можно воспользоваться генератором кода Propel'а. При создании проекта у вас должен создаваться файл config/propel.ini, в котором указаны классы отвечающие за генерацию:
В нашем случае это классы SfPeerBuilder и SfObjectBuilder, которые находятся в плагине sfPropelPlugin.
При изучении этих классов оказалось, что в них есть набор методов, которые вызываются в определенном порядке. В каждый из них передается ссылка на переменную $script. Именуются эти методы по маске add<название_метода_в_сгенерированном_объекте>. Например, addAddInstanceToPool(&$script).
Итак, создаем класс SfPeerBuilderMemcache, где и переопределяем логику SfPeerBuilder
Но так как кэшировать всю модель нам не надо, то сделаем возможным включать и отключать кэш в схеме (schema.yml). Пример:
И добавим в класс SfPeerBuilderMemcache метод, который будет проверять включен или нет кэш для конкретной модели.
Дальнейшую реализацию этого класса оставляю на откуп тем, кому это понадобится… ну или посмотрите исходники в конце статьи :)
Но это еще не все!!! Как я писал в предыдущей статье в случае, когда не используется join'ы при получении связанного объекта Propel вместо retriveByPk() делает запрос в базу, что в нашем случае непозволимо. Чтобы решить эту ситуацию необходимо переопределить класс SfObjectBuilder, а именно метод addFKAccessor, который в случае если связаная модель кэшируется, будет генерировать нужную нам логику:
Теперь нам осталось поменять параметры в файле config/propel.ini на нечто подобное:
Все! Осталось только пересобрать модель.
Кому нужно подробнее покопайтесь в исходниках.
Что получилось в моем случае?
Я включил кэш для модели Юзер. Теперь если я у объекта Photo вызову метод getUser(), он вызовет метод UserPeer::retrieveByPK(). Который и возьмет объект из кэша или из базы, сохранив в кэш. По аналогии с Photo поступят все объекты связанные с User.
UPD: Продолжение
habrahabr.ru/blogs/symfony/76162
Как я уже писал в прошлой статье, чтобы заработал кэш необходимо переопределить 4 метода пула, которые находятся в Peer объектах:
public static function addInstanceToPool($obj, $key = null);
public static function removeInstanceFromPool($value);
public static function getInstanceFromPool($key);
public static function clearInstancePool();
* This source code was highlighted with Source Code Highlighter.
Чтобы не дублировать код для каждого Peer объекта (по наводке пользователя remal), можно воспользоваться генератором кода Propel'а. При создании проекта у вас должен создаваться файл config/propel.ini, в котором указаны классы отвечающие за генерацию:
propel.builder.peer.class = plugins.sfPropelPlugin.lib.builder.SfPeerBuilder
propel.builder.object.class = plugins.sfPropelPlugin.lib.builder.SfObjectBuilder
* This source code was highlighted with Source Code Highlighter.
В нашем случае это классы SfPeerBuilder и SfObjectBuilder, которые находятся в плагине sfPropelPlugin.
При изучении этих классов оказалось, что в них есть набор методов, которые вызываются в определенном порядке. В каждый из них передается ссылка на переменную $script. Именуются эти методы по маске add<название_метода_в_сгенерированном_объекте>. Например, addAddInstanceToPool(&$script).
Итак, создаем класс SfPeerBuilderMemcache, где и переопределяем логику SfPeerBuilder
class SfPeerBuilderMemcache extends SfPeerBuilder
{
protected function addGetPropelCacheStorage(&$script){}
protected function addRemoveInstanceFromPool(&$script){}
protected function addClearInstancePool(&$script){}
protected function addGetInstanceFromPool(&$script){}
}
* This source code was highlighted with Source Code Highlighter.
Но так как кэшировать всю модель нам не надо, то сделаем возможным включать и отключать кэш в схеме (schema.yml). Пример:
user:
_attributes: { phpName: User, cache: on }
* This source code was highlighted with Source Code Highlighter.
И добавим в класс SfPeerBuilderMemcache метод, который будет проверять включен или нет кэш для конкретной модели.
protected function isPropelCacheEnabled()
{
return (boolean)$this->getTable()->getAttribute("cache");
}
* This source code was highlighted with Source Code Highlighter.
Дальнейшую реализацию этого класса оставляю на откуп тем, кому это понадобится… ну или посмотрите исходники в конце статьи :)
Но это еще не все!!! Как я писал в предыдущей статье в случае, когда не используется join'ы при получении связанного объекта Propel вместо retriveByPk() делает запрос в базу, что в нашем случае непозволимо. Чтобы решить эту ситуацию необходимо переопределить класс SfObjectBuilder, а именно метод addFKAccessor, который в случае если связаная модель кэшируется, будет генерировать нужную нам логику:
class SfObjectBuilderMemcache extends SfObjectBuilder
{
protected function addFKAccessor(&$script, ForeignKey $fk)
{
if(!$this->getForeignTable($fk)->getAttribute("cache"))
{
return parent::addFKAccessor($script, $fk);
}
//что-то делаем
}
}
* This source code was highlighted with Source Code Highlighter.
Теперь нам осталось поменять параметры в файле config/propel.ini на нечто подобное:
propel.builder.peer.class = plugins.sfPropelMemcachePlugin.lib.builder.SfPeerBuilderMemcache
propel.builder.object.class = plugins.sfPropelMemcachePlugin.lib.builder.SfObjectBuilderMemcache
* This source code was highlighted with Source Code Highlighter.
Все! Осталось только пересобрать модель.
Кому нужно подробнее покопайтесь в исходниках.
Что получилось в моем случае?
Я включил кэш для модели Юзер. Теперь если я у объекта Photo вызову метод getUser(), он вызовет метод UserPeer::retrieveByPK(). Который и возьмет объект из кэша или из базы, сохранив в кэш. По аналогии с Photo поступят все объекты связанные с User.
UPD: Продолжение
habrahabr.ru/blogs/symfony/76162