Comments 66
Вообще с точки зрения MVC получается правильно: View посредством run просит отдать ему данные.
Интересный пример, над которым стоит подумать. Правда субъективно, хочется что-то более элегантное.
Спасибо за решение :)
Интересный пример, над которым стоит подумать. Правда субъективно, хочется что-то более элегантное.
Спасибо за решение :)
0
Рад, что понравилось. Насчет элегантности - две строчки ведь, куда уж элегантнее?
0
Да я давно уже задаюсь вопросом фрагментарного кэширования в MVC. Философский камень ищу, блин :)
0
настоящая элегантность - это кеширование должно быть вообще прозрачным и для view и для контроллера, а настраиваться где-нибудь отдельно
+1
Спасибо, вроде все чисто. Надо бы перечитать как-нибудь, а то пока голова не варит :-)
0
UFO just landed and posted this here
Вот такую бы штуку еще на PHP, и половина сайтов заработала бы быстрее! :) А пока придется кешировать фрагмментарно :(
-1
Напишите его на php, велика проблема.
+1
Ну вообще-то проблема. Решаемая, конечно, но геморная. Ведь надо знать, менялись ли данные в базе. Можно такой мониторинг организовать, но гораздо удобнее, проще пользоваться готовым кешером, который будет работать на уроване СУБД. И новичкам будет проще. И все сайты, в которых нет кеширования, заработают немного быстрее. Мелочь, а приятно :)
-2
>> Решаемая, конечно, но геморная. Ведь надо знать, менялись
>> ли данные в базе. Можно такой мониторинг организовать,
не могли бы вы порекомендовать пути решения? тоже бьюсь над проблемой "как узнать, expired ли кэш query, не обращаясь к БД" и кроме как "сбрасывать кэш при изменении данных в админке" (вот это действительно ugly :), ничего в голову не приходит
>> ли данные в базе. Можно такой мониторинг организовать,
не могли бы вы порекомендовать пути решения? тоже бьюсь над проблемой "как узнать, expired ли кэш query, не обращаясь к БД" и кроме как "сбрасывать кэш при изменении данных в админке" (вот это действительно ugly :), ничего в голову не приходит
0
Варианты есть разные. Вариант 1: поставить триггеры на изменение и добавление данных. При изменении устанавливать флаг в отдельной таблице. Способ наверное самый простой. Проверку флага можно организовать в хранимой процедуре, которая будет возвращать либо кеш, либо выполнит запрос и вернет новые данные, закешировав их. Если кеш не хранится в базе, достаточно просто получать из базы флаг.
Второй вариант очевиден. Управлять флагом при внесении изменений в базу из модели данных. Т.е. когда PHP/Python/Ruby/C# или что-то там еще отправило данные в таблицу, выставлять флаг (можно в базе, можно вне базы).
А можно и вообще без флагов. При добавлении/изменении данных создавать кеш. Это подойдет, если кеш создается относительно быстро, а добавление/изменение происходит относительно редко.
Ну есть вообщем-то и другие варианты, но их я пожалуй опущу...
Второй вариант очевиден. Управлять флагом при внесении изменений в базу из модели данных. Т.е. когда PHP/Python/Ruby/C# или что-то там еще отправило данные в таблицу, выставлять флаг (можно в базе, можно вне базы).
А можно и вообще без флагов. При добавлении/изменении данных создавать кеш. Это подойдет, если кеш создается относительно быстро, а добавление/изменение происходит относительно редко.
Ну есть вообщем-то и другие варианты, но их я пожалуй опущу...
+2
Часто запросами дело не ограничивается. Вдобавок, результат запроса-то все же достается из кэша и занимает память просто так, не используясь.
0
А если данные грепаются не из базы? А, скажем, из сокета?
0
Меньше-кода, больше-дела, вот это хорошо, спасибо, хорошая статья.
0
Хотите элегантное решение? Оно есть в symfony. Использование компонентов. Мы просто берем и весь фрагмент указываем как компонент. Компонент это такой мини-контроллер, который сам по себе не запускается, а лишь выдает фрагмент, который встраивается на страницу. Кешировать его можно просто как и обычные фрагменты шаблонов.
Короче, нефиг придумывать велосипеды :)
+ из этитх реализаций мне больше всего нравится реализация через модель. Она самая простая.
Короче, нефиг придумывать велосипеды :)
+ из этитх реализаций мне больше всего нравится реализация через модель. Она самая простая.
+1
Так же сие есть в cakephp.
0
В Рельсах от компонентов отказались. Видимо, тому были причины?
-2
В моем фреймворке компоненты тоже есть, конечно. И тем не менее, описанная схема полезна. Впрочем, тут не поспоришь - если не возникает необходимости, то пользоваться и не надо. :-)
+1
Написал апдейт, пояснил.
0
UFO just landed and posted this here
http://zendframework.com/manual/ru/zend.…
есть такой "фронт энд" Zend_Cache_Frontend_Output
+есть еще и другие "фронт энды"
+в Zend_Cache есть еще понятие бэк эндов, т.е. способов хранения кэша например файл, Memcached, sqlite...
+теги к записям, позволяют гибко управлять очисткой кеша.
есть такой "фронт энд" Zend_Cache_Frontend_Output
+есть еще и другие "фронт энды"
+в Zend_Cache есть еще понятие бэк эндов, т.е. способов хранения кэша например файл, Memcached, sqlite...
+теги к записям, позволяют гибко управлять очисткой кеша.
0
UFO just landed and posted this here
На мой взгляд, кэширование SQL запросов как в Рельсе 2, не всегда спасет.
Ведь изменение в БД может производить не только приложение на рельсе, которое управляет и кэшем - к БД может подключаться и стороннее приложение, которое будет вносить изменения в БД, а рельса не будет об этом знать.
Ведь изменение в БД может производить не только приложение на рельсе, которое управляет и кэшем - к БД может подключаться и стороннее приложение, которое будет вносить изменения в БД, а рельса не будет об этом знать.
0
Спасибо.
0
а почему бы не разбить шаблон на блоки, где каждый блок будет иметь контроллер и шаблон? тогда кешировать можно на уровне блоков.
0
Так и делаю, написал выше. Иногда все-таки не все удается разбить, или это породило бы массу дублирования. Пример с последними товарами выбран для простоты. Показательно, что автор подкаста столкнулся именно с проблемой, для которой я предложил решение. То есть это не только мне нужно. ;-)
0
Написал апдейт, пояснил.
0
UFO just landed and posted this here
Насколько я понял основная фишка здесь паттерн Lazy load (или как-то похоже называется). То есть мы в шаблон передаем не данные, а указываем как их получить. А получаются они только в момент реального использования, то есть при работе с темплейтом.
0
Может я зануда и эстет, НО:
- вызывать контроллер из представления логически абсурдно
- пихать в контроллер "модельную" состовляющую - некрасиво
p.s. брызь читать внимательно: http://ru.wikipedia.org/wiki/Model-view-controller
- вызывать контроллер из представления логически абсурдно
- пихать в контроллер "модельную" состовляющую - некрасиво
p.s. брызь читать внимательно: http://ru.wikipedia.org/wiki/Model-view-controller
-1
И если уж такая пьянка, с вызовом данных из представления, то вместо этого порно - "{block action="Mod_Products.blockNewProducts" limit="10"}", можно было бы сделать так: {model="NewsBlock" view="News"}, т.е. указать какую модель данных выполнить и какое представление наложить на всю эту кашу
0
Так никто же не вызывает ничего подобного. Код читали?
0
Кроме MVC push существует еще MVC pull, который и подразумевает вызов контроллера из вью.
+1
>> вызывать контроллер из представления логически абсурдно
почитайте, пожалуйста, Фаулера "Архитектура корпоративных программных приложений", ставшую уже классической.
Станете еще большим занудой и эстетом, но в более правильном направлении ;)
почитайте, пожалуйста, Фаулера "Архитектура корпоративных программных приложений", ставшую уже классической.
Станете еще большим занудой и эстетом, но в более правильном направлении ;)
0
0
Да, это очень похоже, но не совсем то.
В документации:
У меня же этого знать не нужно. Знаем мы только в контроллере, а в шаблоне всегда одно и то же:
Повторюсь: я и так использую Zend Cache, обернув его своим cacher.
В документации:
$res = $cache->foobar('1', '2');
, то есть для выполнения закэшированного нужно все-таки знать, ЧТО должно выполниться.У меня же этого знать не нужно. Знаем мы только в контроллере, а в шаблоне всегда одно и то же:
$res = utils::run( $res );
Повторюсь: я и так использую Zend Cache, обернув его своим cacher.
0
function test()
{
if(!$content = $this->CI->cache->load('top_news', 60*60))
{
$this->CI->view(shablon) - К примеру
$this->CI->cache->save($content, 'top_news');
}
return $content;
}
Получаем нужный результат, все происходит до выполенения View.
Класс за основу брал отсюда: http://larin.in/archives/11
{
if(!$content = $this->CI->cache->load('top_news', 60*60))
{
$this->CI->view(shablon) - К примеру
$this->CI->cache->save($content, 'top_news');
}
return $content;
}
Получаем нужный результат, все происходит до выполенения View.
Класс за основу брал отсюда: http://larin.in/archives/11
0
Фундаментальная проблема - это то, что контроллер никак не может добраться до этого блока, чтобы "контролировать" его.
Мой концепт (action-controller)
...
$this->page()->getLayout()->getLayout()->getBlock('spisokTovarov)->аВотТутМожноВсе();
...
или:
$this->page()->getLayout(2)->getBlock('spisokTovarov)->аВотТутМожноВсе();
Мой концепт (action-controller)
...
$this->page()->getLayout()->getLayout()->getBlock('spisokTovarov)->аВотТутМожноВсе();
...
или:
$this->page()->getLayout(2)->getBlock('spisokTovarov)->аВотТутМожноВсе();
0
Очень полезная идея, эдакий отложенный запуск экшна. Правда есть подозрение, что если подумать, то можно реализовать это элегантнее.
Из замечаний: со статическими вызовом перемудрили, не нужно никаких двух двоеточий, call_user_func умеет принимать на вход массив, в котором первый элемент строка, а не объект - тогда он делает вызов статической функции.
А вообще, спасибо за идею.
Из замечаний: со статическими вызовом перемудрили, не нужно никаких двух двоеточий, call_user_func умеет принимать на вход массив, в котором первый элемент строка, а не объект - тогда он делает вызов статической функции.
А вообще, спасибо за идею.
+1
Спасибо за подсказку про строку, проверю, не знал.
0
Ну, собственно, да - элегантнее можно. По крайней мере в том движке, в котором работаю я, все данные к представлению попадают через специальный объект, который называется "контекст" (в шаблоне он называется $c), так вот:
Контроллер (было):
Контроллер (стало):
Представление (не изменяется):
Как написать
Контроллер (было):
$this->c->someVar = $this->calculateSomeVar( $argument );
Контроллер (стало):
$this->c->jitVar( 'someVar', $this, 'calculateSomeVar', $argument );
Представление (не изменяется):
<?= $c->someVar ?>
Как написать
__get()
надо объяснять?+1
все круто но само по себе кеширование кусков кода или результатов функций это просто
сложнее гораздо когда один и тот же кусок данных используется в нескольких местах) в этом случае при его изменении необходимо сбрасывать кеш со всеми местами где он используется) вот в таком случае не просто получается
сложнее гораздо когда один и тот же кусок данных используется в нескольких местах) в этом случае при его изменении необходимо сбрасывать кеш со всеми местами где он используется) вот в таком случае не просто получается
0
да и вообще КЭШИРОВАТЬ НУЖНО НЕ КУСКИ VIEW а куски данных которые нужны для вью, которые собираются контроллером, кэширование вью это отдельная ступенька
0
У меня, например, сделано так: кэшируются выборки из базы. Каждая выборка- отдельный объект, который может быть поименован согласно того что именно выбирается (это делается как правило на уровне модели), т.е. контроллер спрашивает у модели "записи пользователя 1", модель возвращает выборку и именует ее. Именование идет каскадно. Соотв. по имени можно сбросить все связанные кэши.
Если очень хочеться закэшировать html, то у меня это реализовано приблизительно следующим образом:
1. Выборка передается в шаблон, шаблон пробегается по ней в цикле, при этом непосредственно запрос к БД/кэшу происходит on-demand.
2. Если мы кэшируем какой-то участок шаблона- если кэш не найден, запоминаются все имена произведенных выборок, после чего запоминаем в кэше собствено html и связи с именованными выборками.
3. При изменении модели она сбрасывает все кэши с некоторым именем, как кэши выборок, так и непосредсвенно html.
Сам вызов кэша в шаблоне реализован как активный тег поэтому выглядит все как-то так:
контроллер
Шаблон:
(тупо делаем имя по строке запроса)
Если очень хочеться закэшировать html, то у меня это реализовано приблизительно следующим образом:
1. Выборка передается в шаблон, шаблон пробегается по ней в цикле, при этом непосредственно запрос к БД/кэшу происходит on-demand.
2. Если мы кэшируем какой-то участок шаблона- если кэш не найден, запоминаются все имена произведенных выборок, после чего запоминаем в кэше собствено html и связи с именованными выборками.
3. При изменении модели она сбрасывает все кэши с некоторым именем, как кэши выборок, так и непосредсвенно html.
Сам вызов кэша в шаблоне реализован как активный тег поэтому выглядит все как-то так:
контроллер
$sel= new items_select();
$sel->Where('UserID',eq,$UserID);
//Имя кэша:
$sel->setCacheName('user_items_'.$UserID);
//Постраничный вывод:
$sel->Limit((int)$_REQUEST['page']*10,10);
Шаблон:
(тупо делаем имя по строке запроса)
<!-- op:cache="user_items_{$_SERVER.REQUEST_URI}" lifetime="1000"-->
<!--op:each="$sel"-->
<a href="{$Link}">{$Title}</a>
<!--/op:each-->
<!--/op:cache-->
0
Sign up to leave a comment.
Фрагментарное кэширование в MVC веб-фреймворках