Autor | Zpráva | ||
---|---|---|---|
josh Profil * |
#1 · Zasláno: 3. 2. 2010, 22:59:16
Ahoj,
podle příkladu Jakuba Vrány jsem se nechal inspirovat a udělal jsem si traverzování. Podstatné položky v DB, které tahám, jsou LFT, RGT, LEVEL a NAME, řazeno dle LFT ASC. Úrovně jsou dvě, ale nevím, jak to menu zapsat ve smarty: {foreach from=$menu item='item'} {if $item.lft != ($item.rgt - 1)} <!-- pokud left neni o jednu mensi nez right -> je neco pod tim --> <li><a href="">{$item.name}</a> <ul> <!-- zacneme druhou uroven --> {else} <li><a href="">{$item.name}</a></li> <!-- druha uroven --> {/if} <!-- ted bych potreboval zakoncit seznam druhe urovne, ale nevim jak --> <!-- zkousel jsem opet podminku {if $item.lft != ($item.rgt - 1)}</ul></ul>{/if}, ale ta jej uzavre hned po te, co jej otevre --> {/foreach} Nakopne mě někdo správným směrem? Děkuji. |
||
AM_ Profil |
#2 · Zasláno: 3. 2. 2010, 23:06:38
Tohle je nějaké děsně pofidérní, průběžně tam občas začneš <ul>, ale nikde nevidím, že bys ho ukončoval.
Jinak jestli máš dvouúrovňové menu, vykašli se na stromy a prostě si udělej dvouúrovňový seznam, tohle je opravdu na menu zbtečně těžký kalibr. |
||
josh Profil * |
#3 · Zasláno: 4. 2. 2010, 10:15:23
AM:
děkuji za reakci. Uznávám, že je to možná zbytečně těžký kalibr, měl bys návrh jiného řešení? Potřebuji udělat v administraci webu možnost tvořit stránky tak, aby šlo vytvořit podmenu - dělám to tak, že při tvorbě stránky vyberu stránku nadřazenou (dejme tomu tvořím stránku "Sídlo firmy" a jako nadřazenou jí dám "Kontakty"). V menu budou Kontakty v první úrovni, Sídlo firmy a další kontaktní podstránky ve druhé. V DB tedy ukládám nadřazenou stránku, úroveň zanoření, teď jsem přidal lft a rgt, myslel jsem, že pomůže. Mám tedy ještě přidat nějaký sloupec, nebo toto stačí? Jak bys tuto situaci řešil případně ty? Děkuji. „ale nikde nevidím, že bys ho ukončoval.“ to je v tom komentáři, že bych jej ukončit potřeboval, ale nevím jak :-) |
||
AM_ Profil |
#4 · Zasláno: 4. 2. 2010, 13:16:50
josh:
„V DB tedy ukládám nadřazenou stránku, úroveň zanoření, teď jsem přidal lft a rgt, myslel jsem, že pomůže. Mám tedy ještě přidat nějaký sloupec, nebo toto stačí? Jak bys tuto situaci řešil případně ty?“ Menu není věc, která by se často měnila, a z praktických důvodů nebude obsahovat velká kvanta položek. Pokud si chceš stačí uložit nadřazenou položku, u první úrovně budeš vyplňovat třeba NULL. Pak můžeš renderer menu udělat sice časově neefektivním, nicméně velmi snadným způsobem: - přečteš dotazem všechny položky, které mají rodiče NULL - každou z těchto položek: - vypíšeš - rekurzivně přečteš a vypíšeš všechny položky, kterých je tato rodičem Výsledek uložíš do cache souboru, který invaliduješ pokaždé, když někdo v admin rozhraní pozmění menu. Myslím, že toto vymyslíš mnohem rychleji, než traverzující algoritmus (včetně režie na udržování správných hodnot lft a rgt při změnách menu, která také není zrovna jednoduchá). - pro běžná menu o několika desítkách položek generování menu potrvá stjně jen zlomek vteřiny - bude se to dělat jen jednou po každé změně v menu |
||
josh Profil * |
#5 · Zasláno: 4. 2. 2010, 13:25:47
AM:
> - každou z těchto položek: > - vypíšeš tak budu mít seznam položek první úrovně, ale bez těch subpoložek, ne? „- rekurzivně přečteš“ tohle jsem moc nepochopil, cos tím myslel :-) „Myslím, že toto vymyslíš mnohem rychleji, než traverzující algoritmus“ to ano, vím, že by to nebylo lehké na údržbu, ale nějak bych se s tím (snad) popral. Tohle vypadá líp, jen pochopit tu správnou myšlenku (viz. výše) :-) |
||
AM_ Profil |
#6 · Zasláno: 4. 2. 2010, 13:53:13
Zkusím vysvětlit na příkladu:
function vypismenu($rodic, $odsazeni){ $menu = mysql_query("SELECT id, title FROM menu WHERE parent=$rodic"); while ($item = mysql_fetch_assoc($menu)){ for ($i = 0; $i < $odsazeni*2; $i++) echo ' '; //proste vypis 2*odsazeni mezer, //je na to nejaka funkce ktera to umi bez cyklu ale ted se mi ji nechce hledat, //treba budes odsazovat jinak, takze jen ilustracne echo '<a href="index.php?article='.$menu['id'].'">'.htmlspecialchars($menu['title']).'</a><br>'; vypismenu($menu['id'], $odsazeni+1); } } vypismenu('NULL', 0); |
||
Kcko Profil |
#7 · Zasláno: 4. 2. 2010, 14:07:26
AM:
Zbytecne slozite na DB. Spravne jsi napsal, ze staci dotazem precist polozky co maji rodice NULL. Tady bych to opravil, a nacetl bych vsechny polozky. A rekurzivne je pote vypsal pomoci PHP. Tj. vysledkem bude pouze 1x dotaz. (Mam to ozkousene na navigaci o zhruba 700 polozkach a je to rychle jak peklo). |
||
AM_ Profil |
#8 · Zasláno: 4. 2. 2010, 14:31:50
Kcko:
vlastně jo, když bys to z databáze dostal takhle: "SELECT id, title FROM menu ORDER BY parent" tak by se s tím i docela dalo pracovat. Ale stejně, přibude ti tam pak v PHP režie na třídění těch položek, to už asi bez traverzování tak jednoduše přímo při dotazu do databáze nesetřídíš. Takže si stejně myslím, že na jednoduché menu, které může uživatel upravovat v administraci, stačí tohle, navíc když zapojíš cache, je opravdu jedno, jestli se to poprvé generuje 0.5s nebo 0.005s :) |
||
josh Profil * |
#9 · Zasláno: 4. 2. 2010, 16:02:27
AM:
Použil jsem tvůj script, v DB mám místo NULL 0 (nulu). Když vypíšu vypismenu(0) function vypismenu($rodic) { $menu = mysql_query("SELECT id, name FROM menu WHERE parent=$rodic"); while ($item = mysql_fetch_assoc($menu)) { echo '<li><a href="index.php?article='.$item['id'].'">' . htmlspecialchars($item['name']) . '</a></li>'; vypismenu($item['id']); } } <ul id="menu"> <li><a href="{$ROOT}polozka1/">Polozka1</a> <ul> {php}vypismenu(3){/php} </ul> </li> <li><a href="{$ROOT}polozka2/">Polozka2</a> <ul> {php}vypismenu(15){/php} </ul> </li> <li><a href="{$ROOT}polozka3/">Polozka3</a> <ul> {php}vypismenu(5){/php} </ul> </li> </ul> |
||
larryx Profil |
#10 · Zasláno: 4. 2. 2010, 16:18:52
AM:
> //proste vypis 2*odsazeni mezer, > //je na to nejaka funkce ktera to umi bez cyklu ale ted se mi ji nechce hledat, myslím že to je str_repeat(); |
||
Kcko Profil |
#11 · Zasláno: 4. 2. 2010, 16:23:06
AM:
Staci trivialni funkce ... viz protected function loadCoreData() { global $page; $sql = mysql_query("SELECT * FROM navigace ORDER BY poradi"); while ($r = mysql_fetch_object($sql)) { $this->subcats[ $r->rodic ][] = $r->id; $this->catNames[ $r->id ] = $r->nazev; $this->catParents[ $r->id ] = $r->rodic; $this->level[ $r->id ] = $r->poradi; $this->seo[ $r->id ] = $r->url; //print_r($this->subcats); } } public function printCategories($catIDs, $level = 1, $maxLevel = 999) { global $page; echo "<ul>"; foreach($catIDs as $catID) { //$odkaz = "/" . implode("/",$this->buildHref($catID)); $name = $this->catNames[$catID]; $seo = $this->seo[$catID]; // selected? $totalUrl = $catID."-".$seo; if ($seo == "") $totalUrl = $catID; $selected = ( (int) $page[1] == $catID) ? "class='selected'" : ""; //echo "<div><a href='/$page[0]/$catID-$seo.phtml'$selected >".$name."</a>"; echo "<li><a href='/$page[0]/$totalUrl.phtml'$selected >".$name."</a>"; if( array_key_exists($catID, $this->subcats) && ($catID == $_GET["catID"]) or in_array($catID, $this->rodice)) { //echo $catID; $this->printCategories($this->subcats[$catID], ($level + 1) ); } echo "</li>"; } echo "</ul>"; } |
||
josh Profil * |
#12 · Zasláno: 4. 2. 2010, 16:48:23
Kcko:
to tvoje taky vypadá zajímavě, bohužel OOP není můj šálek kávy.. Můžu se zeptat, zda bys byl tak laskav a přepsal to do procedurálního stavu? Můžeme se pak dohodnout na nějaké odměně, uvědomuji si, že dnes je programátorský čas drahý a zadarmo ani kuře nehrabe :-) |
||
Kcko Profil |
#13 · Zasláno: 4. 2. 2010, 17:03:59
napis mi na ICQ ... mam v profilu, udelam si na tebe vecer cas ...
|
||
josh Profil * |
#14 · Zasláno: 4. 2. 2010, 18:09:32
Děkuji Kckovi za konzultaci a vyřešení problému.
AM: tobě taky dík za snahu a rady. josh. |
||
Časová prodleva: 13 let
|
0