Pull to refresh

Продвинутое и эффективное кеширование страниц в MVC фреймворках

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


Что потребуется



  1. Нужна реализация общего механизма кеша, но не совсем обычная — секрет поддержка тегов
  2. Нужен базовый ORM в каком-либо виде, все что от него требуется это на все сущности, на сохранение и удаление повесить определенные события
  3. Нужна поддержка отложенных запросов — основная идея в том что запрос формируется в контроллере но выполняется при разборе шаблона
  4. Быстрый компилируемый шаблон с поддержкой кеширования — тут от шаблонизатора требуется что-бы он мог полностью заменять обработку куска шаблона содержимым кеша по указанному ключу


Ограничения



данная система подразумевает что фреймворк работает с БД в эксклюзивном режиме — т.е, грубо говоря админка данных реализована в текущем проекте и в базу ручками не лазят.

Реализация



Для затравки, укажу используемые мной инструменты и укажу направдение в котором я двигался:

Система кеширования — просто синглтон который по ключу из драйвера получает значение — все просто как молоток
Теги кеша — базовый наследуемый класс Tag:
class Tag
{
    function __contruct($name)
    {
         $this->name = $name;
    }

    public function buildKey()
    {
         return sprintf('tag_%s_%s', get_class($this), $this->name);
    }

    public function clear()
    {
         $ver = microtime(true).'.'.rand(0, 1000000);
         Cache::GetInstance()->update($this->buildKey(), $ver);
    }
}


Теги реализуются наследованием данного класса и реализацией конструктора «по вкусу».

Теперь можно некоторую запись в кеше пометить набором тегов (тут предполагается что читатель включит фантазию) и сделав clear() тега принудительно сделать все записи кеша содержащие данный тег — не валидными.

Отложенные запросы отлично реализуются с помощью ORM Propel 1.3 — все что вам нужно это запихивать в шаблон объект реализующий SPL Iterator и включающий сформированный объект класса Propel Criteria ну и всякая OOП магия пыха тоже полезна, в данном случае.

На тот-же Propel, путем написания своих билдеров в сущности запихиваются триггеры обнуления тегов:
 class A
 {
     function save(PropelPDO $con)
     {
        ....
        $tag1 = new TagEntity(APeer::CLASS_NAME);
        $tag1->clear();

        if (!$this->isNew())
        {
            $tag2 = new TagPk(APeer::CLASS_NAME, $this->getPrimaryKey());
            $tag2->clear();
        }
        ....
     }
 }


В качетве шаблонизатора использую PHPTAL, к нему пишется кеширующий триггер. Контроллеры имеют примерно следующий вид:
  function executeAction(Context $context)
  {
     $context->addTag('test_tag1', new TagEntity(APeer::CLASS_NAME)); // описываем тег и добавляем ему метку в контексте

     $context->as = APeer::Lazy()->descByDate()->limit(10); // готовим выборку

     $this->renderTemplate('template_name', $context); // рендерим шаблон - да такой у меня API
  }


А шаблон:
 .....
 <div phptal:id="test_tag1">
    <ul>
      <li tal:repeat="a as" tal:content="a/getTitle" />
    </ul>
 </div>
 .....


Вот теперь, при первом запросе сформированное содержимое елемента div попадет в кеш c тегом new TagEntity(APeer::CLASS_NAME), определенным в контроллере (магические триггер щаблонизатора) и пока не будут произведены какие-либо изменения таблицы, описываемой APeer, будет браться из кеша и запросов в БД не будет совсем.

Вместо заключения



Все описанное выше — работает в реальном фреймворке и если хабрасообщество меня приймет то думаю буду писать еще.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.