TIP: Use Markdown or, <pre> for multi line code blocks / <code> for inline code.
These forums are read-only and for archival purposes only!
Please join our new forums at discourse.kohanaframework.org
Как правильно закешировать часть страницы?
  • Всем привет,

    Отчасти мой вопрос будет дублировать вот этот - "Идеологический вопрос Fragment и View", который остался без нормального ответа - http://forum.kohanaframework.org/discussion/8063/Иdeologicheskiy-vopros-fragment-i-view/p1

    Итак, в проекте в шаблонах view используются переменные, тоесть в контроллере никакого вывода через echo нет (если кто кинет ссылкой с разъяснением преимуществ и недостатков echo в контроллере, буду благодарен). Стоит задача кешировать вывод определенных страниц (определенных actions, точнее), при этом то, что генерируется базовым классом контроллера (определено в before - статус сессии, подсчет личных сообщений и тп) - кешироваться не должно. Тоесть, упрощенно говоря - header/footer не кешируем, вывод тяжелой страницы - кешируем, при этом имеем контроль над кешем прямо в контроллере - можем его сбросить, при определенных actions.

    Первый подход был тупо использовать Cache для всех переменных, которые передаются во view. Но в одном из actions их оказалось достаточно много и код получался чрезмерно громоздким. Кроме того, при таком подходе, фактически каждый раз снова делается одна и та же лишняя работа, хотя можно было закешировать вывод и выводить его (отличия есть только для разных языков и статуса сессии).

    Второй попыткой попытался это реализовать через кеширование переменной $this->template->content, но тогда кешировался вообще весь вывод, вместе с header'ом, что не устраивало.

    Дальше был испробован класс Fragment, который вроде как идеально должен подходить для такой задачи (кеширование части страницы). Но вот тут с ним идеологическая непонятка - поставить if блок во view - не проблема, но это не освобождает контроллер от вычислений. Попытался решить это дело проверкой на наличие фрагмента в контроллере, но Fragment::load (единственный способ проверки) делает echo, поэтому вывод дублировался.

    Пока что остановился на написании своего варианта Fragment, у которого есть функция is_cached(), которую можно спокойно вызывать в контроллере и не обсчитывать/передавать переменные, если во view данные будут взяты из кэша и который, помимо i18n учитывает еще и статус сессии (залогинен/разлогинен).

    Но все это очень похоже на костыль, и я пытаюсь понять, какой самый идеологически правильный способ решения данной задачи? Может быть я совсем что-то важное упустил и делаю не так? Или тут красивого решения и нет и нужны вот такие костыли, в чем я сомневаюсь?

    Вобщем, буду благодарен за подсказку - все таки, не один же я с подобной задачей сталкиваюсь (надеюсь). :)

  • По поводу того "чем", то я не понимаю этого мазохизма с фрагментами и кешем ядра, когда есть отличный модуль Cache. Советую apc, memcache или sqllite, они практически всегда быстрее "файлового" варианта.

    по поводу "как", вариантов тут много, в основном от архитектуры Вашего приложения зависит, но не все данные имеет смысл кешировать, надо понимать, что в некоторых ситуациях оно будет только тормозить, речь, например, о часто обновляемых данных и больших массивах. Не стоит забывать и про кеширование на стороне клиента
    http://kohanaframework.org/3.3/guide-api/Controller#check_cache

    Оптимальный вариант - разделяй и властвуй, читай как многоуровневый кеш.

    Например, возьмем каталог интернет-магазина, при запуске контроллера первым делом проверяем check_cache , возможно страница закеширована на стороне клиента и делать ничего не придется. Не закешировалась? ну и ладно :) ищем кеш центрального блока - основного контента(этот вариант скорее подходит для страниц статей например или тех же карточек товаров т.к. обновляются они намного реже каталога), не нашелся и кеш центра (( ладно засучим рукава и сами как большие сделаем запрос к бд, о! первая удача, запрос был закеширован(он и так вибрает только ид нужных нам товаров т.ч. срабатывает мгновенно), пролучив ид'шники товаров данной страницы мы снова лезем в кеш и подгружаем блоки товаров: 1 товар = 1 html блок, это позволит использовать единожды закешированные товары при сортировках и фильтрации каталога. а также в других разделах, например в поиске или каком-нибудь блоке top10 на главной. Сформировали таким образом основной контент, теперь формируем шаблон, в шаблоне понатыканы виджеты, сниплеты и прочее конфети, которое без сопливых знает когда и как ему кешироваться, в общем-то та же ситуация что и с блоками товаров, только тут нам даже и делать ничего не надо, только помянуть их добрым словом). ну и кроме этого мы кешируем ссылки, итоговую конфигрурацию контроллера, переводы для каждой страницы автоматом формируем и т.д. на самом деле даже половины этого будет вполне достаточно :)

  • WinterSilence, спасибо за ответ, но, увы, он далек от сути вопроса.

  • @divan в чем принципиальная разница между кешированием до\после попадания в view или в нем? )) вы собираетесь в каждой вьюхе прописывать это кеширование?

  • Думаю для вставления блоков данных многие используют Request

    Ну например я сделал следующим образом:

    В шаблоне вставляюй некий код Object::factory('top_news', array $params), который ищет например класс Object_Top_News и выполняет в нем метод fetch, который формирует данные передаваемые во вью.

    Вот как то так, но это упрощено очень сильно.

    class Object {
        
        public static function factory($object, $params = array())
        {
            $obj = new $object;
    
            return $obj->render($params);
        }
    
        public function render($params = array())
        {
            if( 
                $this->caching === TRUE 
            AND 
                ! Fragment::load('cache_id', $this->cache_lifetime)
            )
            {
                echo $this->_fetch($params);
                Fragment::save();
            }
            else if( ! $this->caching )
            {
                echo $this->_fetch($params);
            }
        }
    
        protected function _fetch($params)
        {
            $data = $this->fetch($params);
            return View::factory($this->template, $data);
        }
    }
    
    class Object_Top_News extend Object {
    
        public function fetch($params = array())
        {
            $data = DB::select() ..... ;
            return $data;
        }
    }
     

    По такому принципу реализовано у меня в CMS kodicms

    https://github.com/butschster/kodicms/blob/master/cms/modules/widget/classes/model/widget.php

  • @WinterSilence, разница в том, что view использует переменные, которые считаются в контроллере. Соответственно, если мы кешируем уже отрендеренный вывод (прямо во view, с помощью тех же Fragments), то нужно каким-то образом отключить в контроллере просчет этих переменных (это самая тяжелая часть в запросе). И это меня сбивает с толку, потому как, с моей стороны, это вроде как straightforward-функционал, но его нет. Вот я и пытаюсь разобраться, кто из нас с Коханой дурак :) Либо же в контроллере делать render() нужной части страницы и кешировать в контроллере, но вот тут у меня и не получилось. Могу более подробно расписать, если кто-то вообще понял, что я пытаюсь сделать :))

    @ButscH, спасибо, интересный вариант, но тоже слегка мудреный.

  • @divan

    Либо же в контроллере делать render() нужной части страницы и кешировать в контроллере, но вот тут у меня и не получилось.


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

    разница в том, что view использует переменные, которые считаются в контроллере. Соответственно, если мы кешируем уже отрендеренный вывод


    Никто не запрещает кешировать в контроллере сами данные, при сохранении они сериализуются.

    В кохане очень много функционала который как бы есть, но из-за его недоразвитости не используется. Я например вообще Fragment не использую.

  • Кеширование предназначено для ускорения работы. Как по-Вашему, что занимает больше времени - подготовка данных контроллером или рендер шаблона с готовыми переменными? Отсюда и мысль, что собственно кеш шаблона не так важен, как кеш "тяжелых" данных.

    Кеширование шаблонов может быть осложнено многими факторами (глобальные переменные, воздействие на шаблон извне экшена, например в before() или after(), наличие авторизации пользователя и тд). Тут стоит подумать об оформлении отдельных блоков в виде HMVC-запросов (по сути плагины), которые легче воспринимать отдельными компонентами/фрагментами, либо уж кешировать страницу всю целиком.

  • body some_html_code --content_cached-- some html --end_content_cashed-- some_html end-body допустим хотим такую страницу.

    вьюха body some-html <?=$block_static_hard_info;?> yet-somehtml /body

    controller if (!$block_static_hard_info = Cache::instance()->get('block_static_hard_info',false)) { $array = get_all_data_for_subview(); Cache::instance()->set($block_static_hard_info ='block_static_hard_info',View::factory('sybview')->bind('data', $array)); } $this->template->bind('block_static_hard_info',$block_static_hard_info);

    PS когда мы говорим про контроллер ивьюху, мы говорим о том чтобы разделить отображение данных, от обработки параметров обращения и контроль доступа.

    в этом контексте вопрос лишон смысла - почему плохо в контроллере эхом что либо выводить.

    А с практической стороны дела - если контроллер не завершил ещо работу, значит дальше в логике может быть(счас или в будущем при дописывании кода) ситуации с принятием решения о хидерах, - редирект тотже, или эксепшины которые ведут к редиректу или другим хидерам,

    ивот этот эхо вывод сделает не возможным эту работу.

    представь себе работу сайта такой.

    твой код работает и создаёт штмл документы, а юзеры уже смотрят сразу штмл документ. удобно? - да, юзер никогда неувидит ошибки или ещо чего либо, он всегда видит красивые документы.

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

  • Все глаза сломал об этот коммент...

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion