Получение модулей одним запросом

+22
2K
Продолжим начатое, но чуть менее затратно.

Суть проста: зачем мы в магазине будем заставлять нам нести продавца все печеньки, если нам не нравятся диетические. В переводе значит, что мы прямо в запросе к БД будем проверять доступность модуля группе юзера, тем самым уменьшая нагрузку и экономя трафик с БД.
Как видно на демо, для главной страницы оптимизированной версии при дефолтной установке делается на 6 запросов к БД меньше, чем стоковой версии. Чтобы это увидеть поменяйте в блоке справа шаблон: "По умолчанию" и "_default_" — это неоптимизированная версия, "new_default" — оптимизированная. На время генерации можете не смотреть — мускул кэширует запросы сам.

Приступим к выполнению ключевого различия с этим.
1. Выполним запросы к БД:
  1. UPDATE cms_modules SET access_list = REPLACE (access_list, '- ', '- allow');
  2. ALTER TABLE `cms_modules` ADD FULLTEXT(`access_list`);
2. Файл /admin/applets/modules.php
Найти:
  1. 389 и 470 $access_list = $inCore->request('allow_group', 'array_int');
Заменить:
  1. $access_list = $inCore->request('allow_group', 'array');
Найти:
  1. 942 echo '<option value="$group['id'].'"';
  2. if ($do=='edit' && $mod['access_list']){
  3. if (inArray($access_list, $group['id'])){
Заменить:
  1. 942 echo '<option value="allow'.$group['id'].'"';
  2. if ($do=='edit' && $mod['access_list']){
  3. if (inArray($access_list, 'allow'.$group['id'])){
3. Теперь открываем /core/classes/page.class.php и делаем также немаловажное различие:
после:
  1. public $captcha_count = 1;
вставляем:
  1. private static $modules;
Ну и вновь перед последней закрывающейся скобкой вставляем:
  1. public function countThisModules($position){
  2. if (self::$modules === null)self::$modules = self::getThisModules();
  3. return count(self::$modules[$position]);
  4. }
  5. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  6. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  7. private function getThisModules(){
  8.  
  9. $inDB = cmsDatabase::getInstance();
  10.  
  11. //Получаем id пункта меню
  12. $menuid = cmsCore::getInstance()->menuId();
  13. //Проверяем позиции
  14. $strict_sql = !cmsCore::getInstance()->isMenuIdStrict() ? 'AND (m.is_strict_bind = 0)' : '';
  15. //Проверяем доступ
  16. $allow_sql = !cmsUser::getInstance()->is_admin ? "AND (MATCH (m.access_list) AGAINST ('+allow".cmsUser::getInstance()->group_id."' IN BOOLEAN MODE) OR m.access_list = '')" : '';
  17. //Получаем все разрешённые данному юзеру модули для этой страницы
  18. $sql = "SELECT *, m.id as mid, m.template as tpl
  19. FROM cms_modules m, cms_modules_bind mb
  20. WHERE m.published = 1 AND
  21. m.id = mb.module_id AND
  22. (mb.menu_id = '$menuid' OR mb.menu_id = 0)
  23. $strict_sql
  24. $allow_sql
  25. ORDER BY m.ordering ASC";
  26.  
  27. $result = $inDB->query($sql);
  28. if(!$inDB->num_rows($result)){ return false; }
  29. while ($mod = $inDB->fetch_assoc($result)){
  30. $mods[$mod['position']][] = $mod;
  31. }//while
  32.  
  33. return $mods;
  34. }
  35. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  36. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  37. public function printThisModules($position){
  38.  
  39. $inCore = cmsCore::getInstance();
  40. global $_LANG;
  41.  
  42. // Проверяем позиции
  43. if($position=='top' && @$_REQUEST['view']=='search') { return true; }
  44. if(!self::countThisModules($position))return false;
  45.  
  46. foreach(self::$modules[$position] as $mod){
  47. $modulefile = PATH.'/modules/'.$mod['content'].'/module.php';
  48. if (!$mod['user']) { cmsCore::loadLanguage('modules/'.$mod['content']); }
  49. if( !$mod['is_external'] ){
  50. //PROCESS FILTERS
  51. $filters = $inCore->getFilters();
  52. if ($filters){
  53. foreach($filters as $id=>$_data){
  54. require_once PATH.'/filters/'.$_data['link'].'/filter.php';
  55. $_data['link']($mod['content']);
  56. }
  57. }
  58. $callback = true;
  59. $modulebody = $mod['content'];
  60. }
  61.  
  62. if( $mod['is_external'] ){
  63. if (file_exists($modulefile)){
  64. //load module file
  65. require_once $modulefile;
  66. //run module and get its output to $modulebody
  67.  
  68. if ($mod['cache'] && $inCore->isCached('module', $mod['mid'], $mod['cachetime'], $mod['cacheint'])){
  69. $modulebody = $inCore->getCache('module', $mod['mid']);
  70. $callback = true;
  71. } else {
  72. $config = $inCore->yamlToArray($mod['config']);
  73. $inCore->cacheModuleConfig($mod['module_id'], $config);
  74.  
  75. $callback = $mod['content']($mod['module_id']);
  76. $modulebody = ob_get_clean();
  77. if($mod['cache']) { $inCore->saveCache('module', $mod['mid'], $modulebody); }
  78. }
  79. }
  80. }
  81.  
  82. if ( $callback ){ //if module returns TRUE
  83. $module = array();
  84. $mod['body'] = $modulebody;
  85. $smarty = $inCore->initSmartyModule();
  86. if (cmsConfig::getConfig('fastcfg') && cmsUser::getInstance()->is_admin){
  87. $smarty->assign('cfglink', '/admin/index.php?view=modules&do=edit&id='.$mod['mid']);
  88. }
  89. $smarty->assign('mod', $mod);
  90. $module_tpl = file_exists($smarty->template_dir.'/'.$mod['tpl']) ? $mod['tpl'] : 'module.tpl';
  91. $smarty->display($module_tpl);
  92. }
  93. }//foreach
  94. }
  95.  
  96. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  97. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4. Ну и наконец в своём шаблоне (файле template.php) меняем countModules на countThisModules и printModules на printThisModules.

В следующий раз мы изменим printThisModules для другого метода кэширования, но можете даже не надеяться на появление этого в дистрибутиве, ибо у разработчиков совершенно иной взгляд на саму задачу кэширования)
Как именно будет кэшироваться? А очень просто: будут создаваться файлы кэша с простым html или же массивом данных. Это будет на усмотрение модуля, да, кешировать себя будет модуль сам, в зависимости от его приватности и каких либо изменений для каждого пользователя. Например модуль форума: в зависимости от доступа, он может отображать разные темы разным группам (по крайней мере в моей доработке =D), а также у каждого конкретного пользователя разные прочтённые темы, поэтому мы не можем просто взять и закэшировать его. У модуля форума будет по одному файлу на каждую группу, в каждом будет массив, который модуль будет перебирать и отмечать прочтённость топика данным конкретным юзером, а потом отдавать смарти. Хм, что же у нас не для разных групп… Ах, да — Лента. У неё будет один файл для всех групп, в котором просто готовый html.
Я не решил как чистить кеш, либо плагином по эвентам, либо классом логирования, благо всё что можно сделать во фронте, отображается в Ленте.
Ещё важный момент с датами: они просто будут окружаться спаном с timestamp, по которому в закэшированом html легко поменять "5 минут назад", на "вчера во столько то" и ещё с помощью яваскрипта можно будет оживить эти самые "n минут назад" на сайте).
v

UPDATE: патч.
+1
Роман Роман 11 лет назад #
Огромный + за оптимизацию
0
Anonim Anonim 11 лет назад #
Здесь полностью инструкция приведена по установке? Или сначала нужно установить "то"?
0
lokanaft lokanaft 11 лет назад #
Полностью.
0
qwest qwest 11 лет назад #
Скажите а на демо только эта оптимизация или есть еще?
Очень шустро открываются странички.
0
lokanaft lokanaft 11 лет назад #
Хостинг такой.

Еще от автора

Ajax подгрузка контента для двойки
Ну что, товарищи, сегодня вы своими руками сможете сделать ajax подгрузку записей контента.
AJAX подгрузка комментов для двойки
Как следует из названия, дополнение ограничивает полный вывод всех комментов записи и позволяет пользователю при необходимости посмотреть следующие.
ContentWatch - проверка уникальности добавляемого контента для icms2
Компонент позволяет проверять уникальность текста с помощью сервиса Content-Watch.
Используя этот сайт, вы соглашаетесь с тем, что мы используем файлы cookie.