"Деревянные" ссылки |
Утром сегодня сел наконец и переделал класс TNavigation под себя. Возник лишь 1 вопрос: как в дереве ссылки верно собирать из кусков? Я пробовал крутить по-всякому, но решения не нашел. Прошу помочь с последней траблой.
Таблица в БД:
id pid uri title
1 0 about/ О компании
2 1 terms/ Условия использования материалов
3 1 policy/Политика конфиденциальности
Вот код всего класса. $MAIN:ENGINE.ROOT[/]
##############################
##############################
@CLASS
TNavigationDB
##############################
@Init[]
$sitename[$env:SERVER_NAME]
$root[^GetSectionsByParent[0]]
$roll[^Roll[]]
$tempuri[]
##############################
@Roll[]
$urisplit[^MAIN:ENGINE.ROOT.lsplit[/]]
$result[^urisplit.count[]]
##############################
@SectionsCount[pid][tempsection;count]
$count(0)
$tempsection[^GetSectionsByParent[$pid]]
^tempsection.menu{
^if($tempsection.is_published){$count($count+1)}
}
$result[$count]
##############################
@GetSectionsByParent[pid;limit]
$result[^table::sql{
SELECT
id,
pid,
uri,
title,
is_published,
is_admin
FROM
sections
WHERE
^if(def $pid){pid = ^pid.int(0) AND}
is_published = 1
}[^if(^limit.int(0)){$.limit(^limit.int(0))}]]
##############################
@BreadCrops[]
$self.secondnav[^table::create{uri title}]
^self.secondnav.append{$MAIN:ENGINE.ROOT $sitename}
$uri[$request:uri ]
$urisplit[^uri.lsplit[/]]
^urisplit.menu{
^if((^urisplit.line[] > $roll) && (^urisplit.line[] < $urisplit)){
^if(^urisplit.line[] == 1+$roll){
^if(^root.locate[uri;$urisplit.piece/]){
$currentid[$root.id]
^secondnav.append{^if(^urisplit.line[] != ($urisplit - 1)){${MAIN:ENGINE.ROOT}$root.uri} ^taint[as-is][$root.title]}
}
$currenturi[$root.uri]
}{
$tempsection[^GetSectionsByParent[$currentid]]
^if(^tempsection.locate[uri;$urisplit.piece/]){
$currentid[$tempsection.id]
^secondnav.append{^if(^urisplit.line[] != ($urisplit - 1)){${MAIN:ENGINE.ROOT}${currenturi}$tempsection.uri} ^taint[as-is][$tempsection.title]}
}
$currenturi[${currenturi}$urisplit.piece/]
}
}
}
^secondnav.menu{
^if(def $secondnav.uri){
<a href="$secondnav.uri" class=secondnav>^taint[as-is][$secondnav.title]</a>
}{
<b>^taint[as-is][$secondnav.title]</b>
}
}[ ^;> ^;]
##############################
@ShowRoot[]
^root.menu{
^if($root.is_published){
^if($root.uri eq $request:uri){
<a href="${MAIN:ENGINE.ROOT}$root.uri"><b>^taint[as-is][$root.title]</b></a>
}{
<a href="${MAIN:ENGINE.ROOT}$root.uri">^taint[as-is][$root.title]</a>
}
}
}
##############################
@ShowSecondNav[][tempsection]
^if($request:uri ne $MAIN:ENGINE.ROOT){
$uri[$request:uri ]
$urisplit[^uri.lsplit[/]]
^urisplit.menu{
^if((^urisplit.line[] > $roll) && (^urisplit.line[] < $urisplit)){
^if(^urisplit.line[] == 1+$roll){
^if(^root.locate[uri;$urisplit.piece/]){
$currentid[$root.id]
}
$currenturi[$root.uri]
}{
$tempsection[^GetSectionsByParent[$currentid]]
^if(^tempsection.locate[uri;$urisplit.piece/]){
$currentid[$tempsection.id]
}
$currenturi[${currenturi}$urisplit.piece/]
}
}
}
$tempsection[^GetSectionsByParent[$currentid]]
^tempsection.menu{
^if($tempsection.is_published){
^if($tempsection.uri eq $request:uri){
<a href="$tempsection.uri"><b>^taint[as-is][$tempsection.title]</b></a>
}{
<a href="$tempsection.uri">^taint[as-is][$tempsection.title]</a>
}
}
}[<br>]
}
##############################
@ShowSectionsByParent[pid][tempsection]
$tempsection[^GetSectionsByParent[$pid]]
<ul>
^tempsection.menu{
^rem{ *** Как собирать $tempsection.uri??? *** }
^PrintTreeItem[$tempsection;^ShowSectionsByParent[$tempsection.id]]
}
</ul>
##############################
@PrintTreeItem[tempsection;child]
$result[<li><a href="${MAIN:ENGINE.ROOT}$tempsection.uri">$tempsection.title</a>
^if(def $child){<ul>$child</ul>}
</li>]
Все остальное работает. Если где-то можно использовать хэш, чтоб не дергать БД лишний раз - ткните пальцем. Буду благодарен! |
про использования хеша чтобы не делать кучу запросов к БД есть в примерах (Построение деревьев) |
Эт я видел... |
| ...но применительно к моему классу это мало поможет. Но главное - вопрос не в хэше или его отсутсвии. Вопрос в построении ссылок для полного дерева сайта. Тут нужен какой-то прием, которого я не знаю, но наверняка знают завсегдатаи форума. Вот тут я и прошу помощи... |
а передавать глубже полный путь родителя никак? |
Это и требуется |
| только реализация не приходит. я пробовал собирать урлы от родителя - конкретно в дереве не нахожу алгоритма. |
а зачем их собирать? |
брать урл который передали свыше, добавлять слэш, добавлять path текущего объекта и выводить это <a href="тут">...</a>
после этого если есть дочерние объекты то это-же самое передавать глубже. делов-то: один дополнительный параметр. |
Не, они накапливаются. Или я что-то не так делал. Но пробовал так сразу. А теперь посмотрел 32 раз на "Построение деревьев" твое и написал пару методов + заюзал хэш. Теперь все работает, но ты наверняка упростил бы...
Кароче, вот что вышло:
##############################
##############################
@CLASS
TNavigationDB
##############################
@Init[]
$sitename[$env:SERVER_NAME]
$root[^GetSectionsByParent[0]]
$roll[^Roll[]]
$temptable[^table::sql{
SELECT
id,
pid,
uri,
title,
is_published,
is_admin
FROM
sections
}]
$hashTree[^CreateHashTree[$temptable;pid]]
##############################
@CreateHashTree[messages;field]
$result[^messages.hash[$field][$.distinct[tables]]]
##############################
@Roll[]
$urisplit[^MAIN:ENGINE.ROOT.lsplit[/]]
$result[^urisplit.count[]]
##############################
@SectionsCount[pid][tempsection;count]
$count(0)
$tempsection[^GetSectionsByParent[$pid]]
^tempsection.menu{
^if($tempsection.is_published){$count($count+1)}
}
$result[$count]
##############################
@GetSectionsByParent[pid;limit]
$result[^table::sql{
SELECT
id,
pid,
uri,
title,
is_published,
is_admin
FROM
sections
WHERE
^if(def $pid){pid = ^pid.int(0) AND}
is_published = 1
}[^if(^limit.int(0)){$.limit(^limit.int(0))}]]
##############################
@BreadCrops[]
$self.secondnav[^table::create{uri title}]
^self.secondnav.append{$MAIN:ENGINE.ROOT $sitename}
$uri[$request:uri ]
$urisplit[^uri.lsplit[/]]
^urisplit.menu{
^if((^urisplit.line[] > $roll) && (^urisplit.line[] < $urisplit)){
^if(^urisplit.line[] == 1+$roll){
^if(^root.locate[uri;$urisplit.piece/]){
$currentid[$root.id]
^secondnav.append{^if(^urisplit.line[] != ($urisplit - 1)){${MAIN:ENGINE.ROOT}$root.uri} ^taint[as-is][$root.title]}
}
$currenturi[$root.uri]
}{
$tempsection[^GetSectionsByParent[$currentid]]
^if(^tempsection.locate[uri;$urisplit.piece/]){
$currentid[$tempsection.id]
^secondnav.append{^if(^urisplit.line[] != ($urisplit - 1)){${MAIN:ENGINE.ROOT}${currenturi}$tempsection.uri} ^taint[as-is][$tempsection.title]}
}
$currenturi[${currenturi}$urisplit.piece/]
}
}
}
^secondnav.menu{
^if(def $secondnav.uri){
<a href="$secondnav.uri" class=secondnav>^taint[as-is][$secondnav.title]</a>
}{
<b>^taint[as-is][$secondnav.title]</b>
}
}[ ^;> ^;]
##############################
@ShowRoot[]
^root.menu{
^if($root.is_published){
^if($root.uri eq $request:uri){
<a href="${MAIN:ENGINE.ROOT}$root.uri"><b>^taint[as-is][$root.title]</b></a>
}{
<a href="${MAIN:ENGINE.ROOT}$root.uri">^taint[as-is][$root.title]</a>
}
}
}
##############################
@ShowSecondNav[][tempsection]
^if($request:uri ne $MAIN:ENGINE.ROOT){
$uri[$request:uri ]
$urisplit[^uri.lsplit[/]]
^urisplit.menu{
^if((^urisplit.line[] > $roll) && (^urisplit.line[] < $urisplit)){
^if(^urisplit.line[] == 1+$roll){
^if(^root.locate[uri;$urisplit.piece/]){
$currentid[$root.id]
}
$currenturi[$root.uri]
}{
$tempsection[^GetSectionsByParent[$currentid]]
^if(^tempsection.locate[uri;$urisplit.piece/]){
$currentid[$tempsection.id]
}
$currenturi[${currenturi}$urisplit.piece/]
}
}
}
$tempsection[^GetSectionsByParent[$currentid]]
^tempsection.menu{
^if($tempsection.is_published){
^if($tempsection.uri eq $request:uri){
<a href="$tempsection.uri"><b>^taint[as-is][$tempsection.title]</b></a>
}{
<a href="$tempsection.uri">^taint[as-is][$tempsection.title]</a>
}
}
}[<br>]
}
##############################
@ShowSectionsByParent[pid][tempsection]
<ul>
^if($hashTree.[$pid]){
$tempsection[$hashTree.[$pid]]
^tempsection.menu{
^PrintTreeItem[$tempsection.fields;^if($hashTree.[$tempsection.id]){^ShowSectionsByParent[$tempsection.id]}]
}
}
</ul>
##############################
@PrintTreeItem[tempsection;child]
$result[<li><a href="${MAIN:ENGINE.ROOT}^GetFullPath[$tempsection.id]">$tempsection.title</a>
^if(def $child){<ul>$child</ul>}
</li>]
##############################
@GetFullPath[id][temp]
$hashTreeByID[^CreateHashTree[$temptable;id]]
^if($hashTreeByID.[$id]){
$temp[$hashTreeByID.[$id]]
^temp.menu{
^PathPiece[$temp.fields;^if($hashTreeByID.[$temp.pid]){^GetFullPath[$temp.pid]}]
}
}
##############################
@PathPiece[temp;parent]
$result[^trim[$parent]${temp.uri}]
И вопрос вдогонку: как правильней по логике-количеству отжираемой памяти я поступил с хэшами: $hashTree - в Init[] или $hashTreeByID в GetFullPath[id]???
Вопросы, конечно, простые, но очень для меня важные - чтоб в следующий раз не спрашивать |
е-мое... если-б я еще понял что вызывается :) |
1. в Init я вообще ничего-бы не доставал из БД 2. @Init[] - зачем $root[^GetSectionsByParent[0]] а потом $temptable[...]? ведь в temptable вы достанете все, неужели сложно сделать парсерный select? 3. а что живет в secrion.uri? вообще-то ури это типа: /forum/users/ ... если это так то что считать?
немного по коду, не особо вдаваясь в правильность подхода:
@SectionsCount[pid][tempsection;count]
$count(0)
$tempsection[^GetSectionsByParent[$pid]]
^tempsection.menu{
^if($tempsection.is_published){$count($count+1)}
}
$result[$count]
->
@SectionsCount[pid][tempsection]
$result(0)
$tempsection[^GetSectionsByParent[$pid]]
^tempsection.menu{
^if($tempsection.is_published){^result.inc(1)}
}
$result(0)
$tempsection[^GetSectionsByParent[$pid]]
^result.inc($tempsection)
про передачу параметров:
@ShowSectionsByParent[pid;parent_uri][tempsection]
^if($hashTree.[$pid]){
$tempsection[$hashTree.[$pid]]
^tempsection.menu{
^PrintTreeItem[$tempsection.fields;$parent_uri;^if($hashTree.[$tempsection.id]){^ShowSectionsByParent[$tempsection.id;$parent_uri/$tempsection.uri]}]
}
}
</ul>
##############################
@PrintTreeItem[tempsection;parent_uri;child]
<li>
<a href="$parent_uri/$tempsection.uri">$tempsection.title</a>
$child
</li>
И вопрос вдогонку: как правильней по логике-количеству отжираемой памяти я поступил с хэшами: $hashTree - в Init[] или $hashTreeByID в GetFullPath[id]???
вопрос не понят |
Re: альный госу! |
Вот такие ответы я уважаю. И не только я. Все.
И вот что получилось:
##############################
@CLASS
TNavigationDB
##############################
@Init[]
$sitename[$env:SERVER_NAME]
$temptable[^table::sql{
SELECT
id,
pid,
uri,
title,
is_published,
is_admin
FROM
sections
}]
$hashTree[^CreateHashTree[$temptable;pid]]
$root[^GetSectionsByParent[0]]
$roll[^Roll[]]
##############################
@CreateHashTree[sections;field]
$result[^sections.hash[$field][$.distinct[tables]]]
##############################
@Roll[]
$urisplit[^MAIN:ENGINE.ROOT.lsplit[/]]
$result[^urisplit.count[]]
##############################
@SectionsCount[pid][tempsection;count]
$result(0)
$tempsection[^GetSectionsByParent[$pid]]
^result.inc($tempsection)
##############################
@GetSectionsByParent[pid][tempsection]
$result[^table::create{id pid uri title is_published is_admin}]
^if($hashTree.[$pid]){
$tempsection[$hashTree.[$pid]]
^tempsection.menu{
^if($tempsection.pid==$pid){^result.append{$tempsection.id $tempsection.pid $tempsection.uri $tempsection.title $tempsection.is_published $tempsection.is_admin}}
}
}
##############################
@BreadCrops[]
$self.secondnav[^table::create{uri title}]
^self.secondnav.append{$MAIN:ENGINE.ROOT $sitename}
$uri[$request:uri ]
$urisplit[^uri.lsplit[/]]
^urisplit.menu{
^if((^urisplit.line[] > $roll) && (^urisplit.line[] < $urisplit)){
^if(^urisplit.line[] == 1+$roll){
^if(^root.locate[uri;$urisplit.piece/]){
$currentid[$root.id]
^secondnav.append{^if(^urisplit.line[] != ($urisplit - 1)){${MAIN:ENGINE.ROOT}$root.uri} ^taint[as-is][$root.title]}
}
$currenturi[$root.uri]
}{
$tempsection[^GetSectionsByParent[$currentid]]
^if(^tempsection.locate[uri;$urisplit.piece/]){
$currentid[$tempsection.id]
^secondnav.append{^if(^urisplit.line[] != ($urisplit - 1)){${MAIN:ENGINE.ROOT}${currenturi}$tempsection.uri} ^taint[as-is][$tempsection.title]}
}
$currenturi[${currenturi}$urisplit.piece/]
}
}
}
^secondnav.menu{
^if(def $secondnav.uri){
<a href="$secondnav.uri" class=secondnav>^taint[as-is][$secondnav.title]</a>
}{
<b>^taint[as-is][$secondnav.title]</b>
}
}[ ^;> ^;]
##############################
@ShowRoot[]
^root.menu{
^if($root.is_published){
^if($root.uri eq $request:uri){
<a href="${MAIN:ENGINE.ROOT}$root.uri"><b>^taint[as-is][$root.title]</b></a>
}{
<a href="${MAIN:ENGINE.ROOT}$root.uri">^taint[as-is][$root.title]</a>
}
}
}
##############################
@ShowSecondNav[][tempsection]
^if($request:uri ne $MAIN:ENGINE.ROOT){
$uri[$request:uri ]
$urisplit[^uri.lsplit[/]]
^urisplit.menu{
^if((^urisplit.line[] > $roll) && (^urisplit.line[] < $urisplit)){
^if(^urisplit.line[] == 1+$roll){
^if(^root.locate[uri;$urisplit.piece/]){
$currentid[$root.id]
}
$currenturi[$root.uri]
}{
$tempsection[^GetSectionsByParent[$currentid]]
^if(^tempsection.locate[uri;$urisplit.piece/]){
$currentid[$tempsection.id]
}
$currenturi[${currenturi}$urisplit.piece/]
}
}
}
$tempsection[^GetSectionsByParent[$currentid]]
^tempsection.menu{
^if($tempsection.is_published){
^if($tempsection.uri eq $request:uri){
<a href="$tempsection.uri"><b>^taint[as-is][$tempsection.title]</b></a>
}{
<a href="$tempsection.uri">^taint[as-is][$tempsection.title]</a>
}
}
}[<br>]
}
##############################
@ShowSectionsByParent[pid;parent_uri][tempsection]
<ul>
^if($hashTree.[$pid]){
$tempsection[$hashTree.[$pid]]
^tempsection.menu{
^PrintTreeItem[$tempsection.fields;$parent_uri;^if($hashTree.[$tempsection.id]){^ShowSectionsByParent[$tempsection.id;${parent_uri}$tempsection.uri]}]
}
}
</ul>
##############################
@PrintTreeItem[tempsection;parent_uri;child]
$result[<li><a href="${MAIN:ENGINE.ROOT}${parent_uri}$tempsection.uri">^taint[as-is][$tempsection.title]</a>$child</li>]
Всего 1 запрос - тока я считаю, что в конструкторе ему самое место. Если я ошибаюсь по техническим понятиям (много памяти) - поправьте. Но все остальное получилось хорошо. |
вы сами начнете внимательно читать свой же код и думать? |
@GetSectionsByParent[pid][tempsection]
$result[^table::create{idpidurititleis_publishedis_admin}]
^if($hashTree.[$pid]){
$tempsection[$hashTree.[$pid]]
^tempsection.menu{
^if($tempsection.pid==$pid){^result.append{$tempsection.id$tempsection.pid$tempsection.uri$tempsection.title$tempsection.is_published$tempsection.is_admin}}
}
}
вы не задумывались о том, что у вас уже есть в $hashTree? если задумаетесь то поймете, что:
@GetSectionsByParent[pid]
$result[$hashTree.[$pid]]
ведь именно ради этого делается хеш таблиц-то...
@SectionsCount[pid][tempsection;count]
$result(0)
$tempsection[^GetSectionsByParent[$pid]]
^result.inc($tempsection)
ну вы хоть посмотрели на этот код? да, я ошибся при copy/paste ваших кусков, но копировать-то бездумно не надо. на фига тут $result(0) и ^result.inc(...)? на фига @...[...][...;count]?
Всего 1 запрос
это ужасный запрос. он достает всё. а если у сайта 5000 страниц? опять-же, а почему не достать только документы которые is_published = 1? соотв. н нужны будуь ^if($root.is_published){...}
P.S. @ShowSecondNav[] и @BreadCrops[] я даже не смотрел, но на вид они ужасны, хотя-бы потому что там есть .locate в .menu и class=secondnav и не описаны локальные переменные :) |
я делаю, потом думаю |
насчет GetSectionsByParent - каюсь. Остальное по невнимательности. Хотелось похвастаться, что 1 запрос. Но is_published надо проверять только для обычного юзера. Для админа там еще куча примочек для редактирования дерева, потому это далеко не конечный вариант. Тут is_admin тоже не проверяется!
А остальное я сегодня пересмотрю еще раз!
PS: locate выкинуть не удается - нужно переходить к строке таблицы с данным uri, чтобы взять из нее id и идти дальше. Тут как грибы сушеные на шнурках |
1. можно проверять админ это или нет, и если не админ доставать is_published = 1 (а админ смотрит или нет по моему лучше передавать параметром в Init) 2. если есть locate то в 95% случаев его можно заменить на более выстрый поиск в хеше. |
Поиск в хэше |
| Типа менюшить хэш и проверять совпадение uri? Как по-другому? С родительским id все ясно, как это работает. Но вот с полем uri... |
менюшить хэш?? |
| Читай доку лучше [censored] :) |
Когда тебя отдел "Р" щучит - и не такое напишешь... |
| ...ладно, все равно никто не скажет, как locate заменить. Буду сам искать. Спасибо за полминуты уделенного времени! |
:) |
| Всегда пожалуйста, - в реальной жизни, ты бы заслужил порцию матюков. Почитай про хэш вдумчиво и все будет путем. |
Что характерно... |
Я опять что-то не то сделал, потому как ?mode=debug говорит, что стало только хуже. Может, это пока таблица маленькая?
Стало:
$t[^GetSectionsByParent[$currentid]]
$tHash[^CreateHashTree[$t;uri]]
^if($tHash.[$urisplit.piece/]){
$t[$tHash.[$urisplit.piece/]]
$currentid[$t.id]
^secondnav.append{^if(^urisplit.line[]!=($urisplit-1)){${MAIN:ENGINE.ROOT}${currenturi}$t.uri} ^taint[as-is][$t.title]}
}
$currenturi[${currenturi}$urisplit.piece/]
Было:
$tempsection[^GetSectionsByParent[$currentid]]
^if(^tempsection.locate[uri;$urisplit.piece/]){
$currentid[$tempsection.id]
^secondnav.append{^if(^urisplit.line[] != ($urisplit - 1)){${MAIN:ENGINE.ROOT}${currenturi}$tempsection.uri} ^taint[as-is][$tempsection.title]}
}
$currenturi[${currenturi}$urisplit.piece/]
Все локальное описал как полагается. Только вместо locate, который все очень не любят за медленность, сделал хэш и взял из него нужную часть по uri. В отладочном файлике по rusage:
Date IP Comment Usec FSReading Memory for Proccess URI
2004-08-20 22:10:04.562000 127.0.0.1 before 0.0625 0.015625 6880 /articles/design/photoshop/?mode=debug
2004-08-20 22:12:01.937000 127.0.0.1 before 0.046875 0 6876 /articles/design/photoshop/?mode=debug
А в musage:
Date IP Comment Used Free Ever Allocated Since Compact Ever Allocated Since Start URI
2004-08-20 22:10:04.562000 127.0.0.1 before 1216 328 1412.88 1412.88 /articles/design/photoshop/?mode=debug
2004-08-20 22:12:01.937000 127.0.0.1 before 1204 340 1399.54 1399.54 /articles/design/photoshop/?mode=debug
Т.е. старый вариант с locate несколько быстрее. Я правильно понял? |
я не очень понял где искать старые цифры с замерами, т.е. при использовании locate.
Ну а вообще, - если искать нужно среди десятка, другого, то locate будет и быстрее и памяти жрать меньше, но вот когда записей станет штук 100, тогда locate будет отсасывать, громко и неприлично причмокивая :) |
1 результат - "стало", 2 результат - "было". |
Т.е. 1 строка в обоих файлах - с поиском в хэше, 2 - с locate.
В дереве структуры сайта редко бывает больше 100 страниц. Но на этот случай можно написать так:
^if(^SectionsCount[]>100){^через_хэш[]}{^через_locate[]}
Но стоит ли? Еще я заметил, что если активно использовать хэш, то идет работа с файловой системой (FS Reading!=0). |
| херня какая-то, - где цифры замеров для сравнения 2-х способов? |
Забей, Сеня! (©^; Goblin) |
Смысл ясен - в данном случае мне определенно locate выгоднее, потому как он делается в таблице, где 1 раз из 10 будет больше 10 элементов. Хэш посасывает в малых таблицах.
А с цифрами - не партесь. Там, наверное, действительно сложно понять, где что... |