Pull to refresh

Как я подружил «memcache» и Propel в Symfony

Symfony *
Данная статья написана в продолжении поста «ORM – зло или Как я пытался кэшировать Propel в Symfony» по наводки пользователя remal.

Как я уже писал в прошлой статье, чтобы заработал кэш необходимо переопределить 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
Tags:
Hubs:
Total votes 16: ↑14 and ↓2 +12
Views 1.2K
Comments Comments 11