Šablony: Traverzování kolem stromu
- Peetee
- Člen | 75
Ahoj,
pokouším se v šabloně vypsat strom, který vznikl metodou Traverzování kolem stromu. Takže je seřazený a má proměnou hloubka, která určuje zanoření položky – více v části s „Výpis stromu do seznamu s odrážkami“ – chtěl bych to vypsat přesně do stromu s odrážkami
Chci zeptat, jestli je to dobrý nápad – jestli je dobrý nápad sestavovat takto strom v šabloně.
Pokoušel jsem se upravit příklad z Dědičnost bloků – konkrétně:
{block #menu}
<ul>
{foreach $menu as $item}
<li>{if is_array($item)} {include #menu, 'menu' => $item} {else}{$item}{/if}</li>
{/foreach}
</ul>
{/block}
Ale tam mi přijde zbytečné transformovat to pole menu, aby jednotlivé položky byly zase pole menu a ty by byly taky pole atd… když už to mám takle pěkně seřazený…
Moc děkuju za každej nápad.
- Ondřej Mirtes
- Člen | 1536
Před nějakou dobou jsem v Nette taky traverzování kolem stromu dělal, taky na základě článku Jakuba Vrány. A pokud se nemýlím, tak tato metoda stromového výpisu je výjimečná právě tím, že se nevypisuje rekurzivně.
Myslím, že v této metodě by se vnořování v <ul> dalo zajistit detekcí změny hloubky oproti předchozí položce a na základě toho vypsat nějaké ukončování <ul> (vnořeného) a <li>… Bude to chtít trochu přemýšlení a experimentování, aby výsledek byl vždy validní, ale půjde to.
- toka
- Člen | 253
Experimentoval jsem takto dlouho, když jsem chtěl vypsat do šablony
sitemap
, a musím říct, že jsem byl tak netrpělivý a
rozladěný výsledkem a nechtělo se mi nad tím myslet, půl páté ráno, že
jsem se na to vykašlal :-) Ale zamínkou bylo vypsat nejen seznam, správně
zanořený, což mi funguje, ale i mít možnost udělat odkazy – tedy
každý prvek je pole. Šel jsem na to tak, že jsem přidal do pole klíč
hasChild
a podle něho chtěl ověřovat následnou potřebu
volání rekurze, či nikoliv, ale ještě jsem to nedokončil. Proto bych se
rád seznámil s Vaším řešením, pokud to není tajemství :-) Díky.
- srigi
- Nette Blogger | 558
Robim teraz na niecom, kde sa „Nested set“ pouziva a mam to celkom pekne vyriesene. Ako Model pouzivam Doctrine a ten Nested set podporuje nativne nad tabulkou. Ked si „fetchnem“ cely jeden strom, tak mi Model vrati cca toto:
Array
(
[id] => 23
[root_id] => 22
[lft] => 2
[rgt] => 9
[level] => 1
)
Array
(
[id] => 27
[root_id] => 22
[lft] => 3
[rgt] => 4
[level] => 2
)
Array
(
[id] => 28
[root_id] => 22
[lft] => 5
[rgt] => 6
[level] => 2
)
Array
(
[id] => 29
[root_id] => 22
[lft] => 7
[rgt] => 8
[level] => 2
)
Array
(
[id] => 24
[root_id] => 22
[lft] => 10
[rgt] => 15
[level] => 1
)
Array
(
[id] => 30
[root_id] => 22
[lft] => 11
[rgt] => 12
[level] => 2
)
Array
(
[id] => 31
[root_id] => 22
[lft] => 13
[rgt] => 14
[level] => 2
)
Array
(
[id] => 25
[root_id] => 22
[lft] => 16
[rgt] => 17
[level] => 1
)
Array
(
[id] => 26
[root_id] => 22
[lft] => 18
[rgt] => 19
[level] => 1
)
Doctrine umoznuje viac stromov v jednej tabulke, root nodu vynechavam, lebo by mi svietila ako rodic nultej urovne a ak by som kcel vytvorit jej ‚sibling‘, musel by som robit novy strom.
Nody su uz usporiadane a ako vidno nie su ulozene rekurzivne (vid. vyssie Ondrej). Na ich vykreslenie pouzivam takuto sablonu:
<ul>
{? $temp = 1; }
{foreach $tree as $node}
{if $node->level > $temp}
<ul>
{? $temp = $node->level;}
{elseif ($node->level == $temp) && (!$iterator->isFirst())}
</li>
{elseif $node->level < $temp}
</li></ul></li>
{? $temp = $node->level;}
{/if}
<li><a href="{plink Foo:bar 'id'=>$node->id}">{$node->name}</a>
{/foreach}
</li>
</ul>
Generuje to validny HTML kod cca:
<ul>
<li>
<a href="">Node name</a>
<ul>
<li><a href="">Subnode name</a></li>
...
</ul>
</li>
...
cize vnorene UL je „zakomponovane“ este v nadradenom LI, tak ako som to
potreboval
(a ako je to spravne podla W3C). Sablona si do $temp
uklada
aktualny level
a v jednotlivych iteraciach sa if
podmienka pozera, ci level klesa, stupa alebo je bez zmeny a podla toho
renderuje. Pouzivam tam este premennu $iter
aby sa mi hned po
v prvej iteracii nevyrenderovalo uzatvaracie </li>
, toto
treba trocha zrefaktorovat a vyuzit ten iterator, co je ako pomocna premenna
v loopoch v sablonach.
Inak ked som hladal tuto vec po nete, nasiel som, ze ludia zo Symfony a
Propel renderuju Nested set uplne rovnako (odkladaju si level do docasnej
premennej), takze je toto riesenie IMO spravne.
enjoy.
Edit: este pripomeniem, ze tato sablona umoznuje renderovat strom neobmedzenej hlbky, nie len do druhej urovne ako je v ukazke vyssie (je to len priklad). Okrem tohom nody v mojom priklade su objekty, nie len polia, preto na nich mozem volat rozne pomocne metody potrebne k renderu. Priklad je ale IMHO dostatocne zrozumitelny.
Editoval srigi (9. 7. 2010 6:45)
- Vyki
- Člen | 388
Já osobně používám základní myšlenku tohoto: https://forum.dibiphp.com/…34-fetchtree.
Je to rekurzivní tvoření stromu (pole) dle záznamů z DB na základě
vztahu $id
a $parent_id
. Jsou tam velmi pěkně
použity reference polí. Celý ten strom si ukládám do cache aby to vždy
při tvoření menu nemuselo sahat do DB. Pro vypisování toho menu potom také
používám ten příklad z dědičnosti bloků.
- Ani
- Člen | 226
Trochu to tu zneužiju.
Můžu se jen zeptat, proč všichni vypisujete tyhle menu do <ul>
<li>, snad jedině, že to jsou značky na seznam? Já to vždycky řešim
jen jako normální odkazy, který si upravím pomocí css a .depth1, .depth2…
Dělám něco špatně?
Jinak já si celý menu z db tahám jako ->fetchAssoc(‚parent_id,id‘) a to pak projedu poměrně jednoduchou i docela rychlou rekurzivní funkcí. A vykreslení už je jednoduchý, přes foreach.
Editoval Ani (10. 2. 2010 1:15)
- srigi
- Nette Blogger | 558
Ani napsal(a):
Trochu to tu zneužiju.
Můžu se jen zeptat, proč všichni vypisujete tyhle menu do <ul> <li>, snad jedině, že to jsou značky na seznam?
Ide o to, že strom vyrenderovany do UL-LI zoznamu sa ti vykresli ako strom aj pri vypnutom stylovani. Tvoje riešenie IMO zlyha (z vizualnej stránky veci) pri vypnutom CSS. A navyše je renderovanie do UL-LI nezávisle na hĺbke stromu. Ty ak vo svojej metode nepripravys štýly pre hĺbku 5 a viac, tak už paturovnove menu sa nebude vykreslovat správne. A okrem toho je to semantickejsie ako nejaké ahref-y v dive.
- iguana007
- Člen | 970
Ahoj srigi,
prosimte, mel bych na tebe dotaz, pokousel jsem se implementovat tvuj priklad
(http://bit.ly/bAVvlc)
tykajici se nested set. Jde mi o to, ze mam v databazi nested strom odkazu,
z ktereho bych rad vykreslil UL>LI dropdown menu.
Myslim, ze jsem vse pochopil spravne, ale narazil jsem na error, ktery na me pri
renderu menu vyskoci:
Call to undefined method DibiRow::getActive()
Predpokladam, ze to po me bude chtit i ty dalsi metody z sablony, mohl by si
mi prosim popsat, co tyto metody maji presne delat?
Diky moc za kazdou radu.
- srigi
- Nette Blogger | 558
iguana007 napsal(a):
Ahoj srigi,
prosimte, mel bych na tebe dotaz, pokousel jsem se implementovat tvuj priklad (http://bit.ly/bAVvlc) tykajici se nested set. Jde mi o to, ze mam v databazi nested strom odkazu, z ktereho bych rad vykreslil UL>LI dropdown menu.
Myslim, ze jsem vse pochopil spravne, ale narazil jsem na error, ktery na me pri renderu menu vyskoci:
Call to undefined method DibiRow::getActive()
Predpokladam, ze to po me bude chtit i ty dalsi metody z sablony, mohl by si mi prosim popsat, co tyto metody maji presne delat?
Diky moc za kazdou radu.
Hello, ide o to, ze som ten svoj priklad neocistil – pri vykreslovani LIcka si vsimni, ze je zistovanie „aktivnosti“. Len to vyhod z kodu a pojde ti to.
ide o to, ze ja som do View sablony predaval tzv. Doctrine_List co je hentamto pole – v skutocnosti su to objeky Doctrine_Record, ktore je mozne previest na pole. No a ja som ich rozsiril o metodu getActive()
Sypem si popol na hlavu
edit: upravil som povodny prispevok. Kod je tam upraveny (ocisteny), je tam pouzity aj ten $iterator, takze si to updatnite.
Editoval srigi (9. 7. 2010 6:47)
- iguana007
- Člen | 970
Tak odvolávám – v tom příkladu, jak to vykreslit v té šabloně je někde chyba, protože se mi ten strom od určité části začne renderovat špatně – tj. přestane to uzavírat prvky, dám sem příklad:
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item - zde mi to zacne renderovat spatne
Item
Item
Item
Item
Item
Item
Item
Item
Item
Item
Přijde mi právě divné, že to zkolabuje někde uprostřed a ne třeba
u prvního výskytu levelu 3 apod. Nějaké nápady co s tím prosím?
Řeším to už celý den a už vážně nevím co by mohlo být špatně.
Díky za každou radu.
- Peetee
- Člen | 75
Ahoj,
děkuji všem přispívajícím, sice již je to poměrně dlouho, ale tento problém řeším pravidelně, proto si dovolím připojit upravené řešení od srigi, ještě jednou děkuji!
<ul>
{? $temp = 1; }
{foreach $tree as $node}
{if $node->level > $temp}
<ul>
{? $temp = $node->level;}
{elseif ($node->level == $temp) && (!$iterator->isFirst())}
</li>
{elseif $node->level < $temp}
{? $a=str_repeat("</li></ul></li>",$temp-$node->level)}
{!$a}
{? $temp = $node->level;}
{/if}
<li><a href="{plink Foo:bar 'id'=>$node->id}">{$node->name}</a>
{/foreach}
{? $a=str_repeat("</li></ul></li>",$temp)}
{!$a}
</ul>
Budu rád za komentáře.
Editoval Peetee (27. 9. 2010 22:55)
- macesko
- Člen | 12
Ahoj,
nevim jestli jsi to testoval, ale nasel jsem tam chyby. Trochu jsem to
upravil.
<ul>
{? $temp = 1; }
{foreach $pages as $node}
{if $node['depth'] > $temp}
<ul>
{? $temp = $node['depth'];}
{elseif ($node['depth'] == $temp) && (!$iterator->isFirst())}
</li>
{elseif $node['depth'] < $temp}
</li>
{? $a=str_repeat("</ul></li>",$temp-$node['depth'])}
{!$a}
{? $temp = $node['depth'];}
{/if}
<li><a href="{plink Foo:bar 'id'=>$node->id}">{$node->name}</a>
{/foreach}
</li>
{? $a=str_repeat("</ul></li>",$temp-1)}
{!$a}
</ul>
Editoval macesko (5. 11. 2010 3:23)