DLMenu и препаре

Добрый день.

Вопрос по препаре. Делаю мега-меню, и так получается, что количество запросов в базу с препаре значительно больше, чем при использовании вложенных снипетов.
Код.
1. Начал с варианта вложенных сниппетов, но сначала посмотрел количество вызовов вообще без меню — 29 (это главная страница со множеством анонсов).
Итак, вызов меню такой (html привожу в сокращенном виде)

[[DLMenu?
&prepare=`preparemenu`
&parents=`0`
&maxDepth=`2`
&hereClass=`active`
&countChildren=`0`
&outerTpl=`@CODE: <ul>[+wrap+]</ul>`
&rowTpl=`@CODE:<li><a href="[+url+]" title="[+title+]">[+title+]</a></li>`
&innerTpl=`@CODE:<div class="navbar-dropdown navbar-dropdown-single">
                      <ul>[+wrap+]</ul>
                 </div>`
&parentRowTpl=`@CODE:<li><a href="[+url+]" title="[+title+]">[+title+] <span class="open-dropdown"><i class="fa fa-angle-down"></i></span></a>[+wrap+]</li>`
&categoryFolderTpl=`categoryTpl`
]]


preparemenu — для подмены шаблона, т.к. мега-меню нужно не для всех пунктов, взят отсюда

А дальше невообразимая матрешка
Чанк categoryTpl:
<li><a href="[+url+]" title="[+title+]">[+title+] <span class="open-dropdown"><i class="fa fa-angle-down"></i></span></a>
	<div class="navbar-dropdown">
[[DocLister? &parents=`[+id+]` &depth=`0` &tpl=`cat-main` &showParent=`0` &orderBy=`menuindex ASC`]]
	</div>
</li>

Чанк cat-main:
<div class="col-md-3">
	<ul>
		<li class="label">[+pagetitle+]</li>
[[DocLister? &parents=`[+id+]` &depth=`0` &tpl=`cat_tpl` &showParent=`0` &orderBy=`menuindex ASC`]]
	</ul>
</div>

Чанк cat_tpl:
<li><a href="[+url+]" title="[+title+]">[+title+]</a></li>

Посмотрел статистику — 37 запросов в базу. 29 уже было, итого — 8 запросов (в мегаменю 5 категорий, в каждой около 10 подкатегрий).

2. То же самое, но уже через прпаре
[[DLMenu?
&prepare=`preparemenu,megamenu`
&parents=`0`
&maxDepth=`2`
&hereClass=`active`
&countChildren=`0`
&outerTpl=`@CODE: <ul>[+wrap+]</ul>`
&rowTpl=`@CODE:<li><a href="[+url+]" title="[+title+]">[+title+]</a></li>`
&innerTpl=`@CODE:<div class="navbar-dropdown navbar-dropdown-single">
		    <ul>[+wrap+]</ul>
		</div>`
&parentRowTpl=`@CODE:<li><a href="[+url+]" title="[+title+]">[+title+] <span class="open-dropdown"><i class="fa fa-angle-down"></i></span></a>[+wrap+]</li>`
&categoryFolderTpl=`@CODE:<li><a href="[+url+]" title="[+title+]">[+title+] <span class="open-dropdown"><i class="fa fa-angle-down"></i></span></a>
				<div class="navbar-dropdown">
				    [+category+]
				</div>
			</li>`]]

Препаре megamenu:
<?php
$data['category'] = $modx->runSnippet("DocLister", array(
	'parents' => $data['id'], 
	'prepare' => function($data, $modx, $_DL) {
            $data['cate_list'] = $modx->runSnippet("DocLister", array(
			'parents' => $data['id'],
			'ownerTPL' => '@CODE:[+dl.wrap+]', 
			'orderBy' => 'menuindex ASC',
			'tpl' => '@CODE:<li><a href="[+url+]" title="[+title+]">[+title+]</a></li>'));
		return $data;},
	'ownerTPL' => '@CODE:[+dl.wrap+]', 
	'orderBy' => 'menuindex ASC',
	'tpl' => '@CODE:<div class="col-md-3">
                     	<ul>
                            <li class="label"><a href="[+url+]" title="[+title+]">[+title+]</a></li>
			    [+cate_list+]
                       	</ul>
                    </div>'));
return $data;


Смотрю статистику. Нет, я конечно, особого чуда не ожидал, но и такой засады тоже — 114 запросов! Итого 114-29=85 запросов вместо 8 при вложенных сниппетах.

Вопрос — что не так? И как правильно.
Спасибо.

10 комментариев

avatar
В первый раз [+category+] считалось только для пунктов, подходящих под categoryFolderTpl, а во втором — для каждого пункта меню на двух уровнях. Очевидно, дело в этом и надо какое-то доп.условие в prepare :)
avatar
Спасибо.
Попробовал в препаре megamenu поменять
<?php
$data['category'] = $modx->runSnippet("DocLister", array(
        'parents' => $data['id'],
        ...

на
<?php
$data['category'] = $modx->runSnippet("DocLister", array(
        'parents' => '2',
        ...

Где 2 — это id, от которого нужно выстроить мега-меню. Ожидания не оправдались — стало еще больше, вместо 114 теперь 170 (((
avatar
Мне кажется я совершенно о другом писал. Prepare вызывается на каждый пункт в меню, т.е. каждого элемента каждого из двух уровней меню (maxDepth=2) вызывается DocLister с поиском. И пытается для каждого из этих пунктов/подпунктов меню сформировать плейсхолдер category. Отсюда и запросы. А нужно, чтобы он вызывался только для тех пунктов, которые подходят под условия применения шаблона categoryFolderTpl.

К тому же, т.к. в доклистере везде идет запрос дочерних, то его все это можно сделать сразу в рамках DLMenu за счет установки разных шаблонов в зависимости от уровня документа $data['level']

[+_renderRowTpl+] — если установлен, то его значение будет использовано в качестве шаблона при выводе документов;
[+_renderOuterTpl+] — если установлен, то его значение будет использовано в качестве шаблона при выводе обертки дочерних документов.
avatar
На уровне подсознания я понимаю, о чем речь, — препаре отрабатывает независимо от того, что я вывожу. Т.е. нужно ограничивать не вывод, а работу самого препаре еще до вывода — чтобы он не делал лишнюю работу. Как сделать не могу врубиться((

Кстати, убрал препаре preparemenu — хз, но DLMenu c добавленным этим препаре categoryFolderTpl продолжает работать как ни в чем не бывало… Что-то я перемудрил.
avatar
убрал препаре preparemenu
— там пример совершенно про другое — как применить шаблон categoryFolderTpl там, где он по-умолчанию не применяется (а именно, когда у данного ресурса «нет детей»). Но оттуда можно почерпнуть принцип действия того, что нам нужно: вызывать отработку препаре только там, где должен быть шаблон categoryFolderTpl :)
avatar
Такая мысль была — в preparemenu запихнуть megamenu, но будет опять «матрешка», только с другого боку.
avatar
В общем, скрестил два препаре, получилось так

<?php
if (strpos($data['link_attributes'],'category') !== false) {
	$data['category'] = $modx->runSnippet("DocLister", array(
	'parents' => $data['id'],
	'prepare' => function($data, $modx, $_DL) {
            $data['cate_list'] = $modx->runSnippet("DocLister", array(
			'parents' => $data['id'],
			'ownerTPL' => '@CODE:[+dl.wrap+]', 
			'orderBy' => 'menuindex ASC',
			'tpl' => '@CODE:<li><a href="[+url+]" title="[+title+]">[+title+]</a></li>'));
		return $data;},
	'ownerTPL' => '@CODE:[+dl.wrap+]', 
	'orderBy' => 'menuindex ASC',
	'tpl' => '@CODE:<div class="col-md-3">
                     	<ul>
                        <li class="label"><a href="[+url+]" title="[+title+]">[+title+]</a></li>
			    [+cate_list+]
                       	</ul>
                    </div>'));
}
return $data;

По количеству запросов, как и при вложенных сниппетах — 37, из которых на меню приходится 8.
avatar
Ну наконец-то :) А какой результат ожидался? :) Я думаю, что уменьшить количество запросов можно попытаться разве что пересмотром изначальной концепции — вызовом сразу с maxDepth=4 и последующим разруливанием шаблоном на уровне prepare. Ну а перенос тех же вызовов из шаблона в prepare всего-лишь в теории несколько сокращает время отработки запроса (за счет того, что не нужно парсить повторно шаблоны для замены вызовов сниппета — они вызываются прямо в виде метода runSnippet). Но это уже на уровне заморочек и не факт, что сэкономив на запросах мы не увеличим время этих запросов или время на обработку php. А из проделанной работы разве что один плюс — удалось получше вникнуть в работу prepare, чтобы вернуть количество запросов от 140 назад к 8 :) ))
avatar
Как и сообщал в первом посте — чуда не ожидал, хотелось оптимизировать матрешку + во всех обсуждениях вложенные сниппеты не приветствуются. Да и для дальнейшего повторения удобнее. Ранее подобное делал стилями, что тоже не айс, а сейчас захотелось сделать по-другому, «шаблонизировать» если можно так сказать.

А из полезного — да, узнал другую сторону медали препаре, не всегда он «животворящий», можно собственными руками выстрелить себе в ногу))
avatar
Итого через DLMenu в препаре лучше, чем через DL — 4 запроса (против 8), препаре megamenu такой:

<?php
if (strpos($data['link_attributes'],'category') !== false) {
$data['category'] = $modx->runSnippet("DLMenu", array(
	'parents' => $data['id'],
	'maxDepth' => '2',
	'outerTpl' => '@CODE: [+wrap+]',
	'parentRowTpl' => '@CODE:<div class="col-md-3">
                     	<ul>
                        	<li class="label"><a href="[+url+]" title="[+title+]">[+title+]</a></li>
							[+wrap+]
                       	</ul>
                    </div>', 
	'rowTpl' => '@CODE:<li><a href="[+url+]" title="[+title+]">[+title+]</a></li>'
));
}
return $data;
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.