Rekurze v šabloně se zacyklí

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Pan Dobrman
Člen | 45
+
0
-

Dobrý den, snažil jsem se převést tento kód do šablony:

	private function buildTree($parent2 = null)
	{
		foreach($this->menu as $name => $parent)
		{
			if($parent == $parent2)
			{
				echo $name;

				$this->buildTree($name);
			}
		}
	}
{block #menu}
	{var $parent2 = null}

	{foreach $menu as $name => $parent}
		{if $parent == $parent2}
			{$name}

			{include #this, parent2 => $name}
		{/if}
	{/foreach}
{/block}

V php vše funguje v pořádku, jen v latte se zacyklí a vyhodí výjimku „Maximum function nesting level of ‚100‘ reached, aborting!“. Kde jsem udělal chybu?

Editoval Pan Dobrman (17. 7. 2012 22:08)

vvoody
Člen | 910
+
0
-
{var $parent2 = null}
{block #menu}
        {foreach $menu as $name => $parent}
                {if $parent == $parent2}
                        {$name}

                        {include #this, parent2 => $name}
                {/if}
        {/foreach}
{/block}
Pan Dobrman
Člen | 45
+
0
-

Děkuji

Pan Dobrman
Člen | 45
+
0
-

Bylo by možné v latte vytvořit, aby všechny poslední položky v každé větvi menu byly tučným písmem? Například takto:

  • Menu 1
    • Submenu 1
      • Subsubmenu 1
    • Submenu 2
  • Menu 2

Pokusil jsme se použít makro last, ale to mi vždy označí tučným písmem jen poslední položku z úplně poslední větve (v příkladu položku „Submenu 2“).

{var $parent2 = null}
{block #menu}
        {foreach $menu as $name => $parent}
                {if $parent == $parent2}
                        {last}<strong>{/last}{$name}{last}</strong>{/last}

                        {include #this, parent2 => $name}
                {/if}
        {/foreach}
{/block}

Byl bych moc vděčný za radu. Děkuji

Editoval Pan Dobrman (18. 7. 2012 15:55)

vvoody
Člen | 910
+
0
-

Ty mas v $menu vsetky polozky a vzdy prechadzas uplne vsetky takze last moze byt len jedno. Mozno by si mohol vyuzit css selector :last-child alebo to menu poskladat este niekde popredu v modely a potom ho uz len takto vypisat s tym ze uz nebudes hladat vo vsetkych jeho polozkach, alebo do tretice :D ak to menu mas v DB tak to ide aj priamo s tym ze staci vlozit do sablony len selection na menu polozky s parentom NULL.

Pan Dobrman
Člen | 45
+
0
-

Děkuji za odpověď. Já měl za to, že pokud procházím pomocí rekurze, takže budu moci uplatnit makro last na více položek. Selector „:last-child“ by pro mě byl ideální, ale zjistil jsem, že bych potřeboval přidat ještě odkaz na vytvoření nové položky (což musím řešit v šabloně, protože přes css to nejspíše neudělám). V modelu jsem to nechtěl skládat, protože mi přijde čistější to udělat až v šabloně. Je něco takového možné v latte? Už se o to snažím skoro dvě hodiny, ale né a né na to přijít :).

vvoody
Člen | 910
+
0
-

V sablone sa neprogramuje! :D alebo aspon co najmenej, data si priprav v modely aby si mal sablonu co najmenej zasvinenu kadejakymi podmienkami. V tvojom pripade aby si prechadzal vzdy len polozky menu danej urovne a nie vsetky, potom makro last bude krasne splnat svoj ucel.

Pan Dobrman
Člen | 45
+
0
-

Data mám předpřipravené tak, že při požadavku se mi vrátí pole ve tvaru ‚název‘ ⇒ ‚rodič‘. Pokud jsem vás správně pochopil, tak bych měl ke zpracování do šablony odeslat vždy jen jednu hlavní větev? např.:

1. cyklus

  • Menu 1
    • SubMenu 1
      • SubSubMenu 1 #nebude označeno jako last
    • SubMenu 2 #last

2. cyklus

  • Menu 2 #last
vvoody
Člen | 910
+
0
-

Myslel som to tak ze si to pole v modely transformujete tak aby bolo viacurovnove a odpovedalo strukture menu

Pan Dobrman
Člen | 45
+
0
-

Mockrát děkuji za vás nápad. Výsledek vypadá takto (kód je ošklivý, psal jsem ho narychlo):

Komponenta:

	public function render()
	{
		$return = array();
		$this->generateTree($this->menu, null, $return);
		$this->template->menu = $return;
		$this->template->render();
	}

	private function generateTree($menu, $_parent = null, &$return)
	{
		foreach($menu as $name => $parent)
		{
			if($_parent == $parent)
			{
				$return[$name] = null;
				unset($menu[$name]);
				$this->recurse($menu, $name, $return[$name]);
			}
		}
	}

Latte:

{var $_menu = $menu}
{block #menu}
	<ul> /* Zatím nefunguje */
	{foreach $_menu as $name => $parents}
				<li>
					{$name}
					{if $parents != null}
						{include #this, _menu => $parents}
					{else}
						Přidat novou položku
					{/if}
				</li>
	{/foreach}
	</ul>
{/block}

Editoval Pan Dobrman (18. 7. 2012 19:16)

vvoody
Člen | 910
+
0
-

Ten vystup je podla vysich predstav? Ten else by som asi nahradil makrom last, teda ak spravne chapem ze „pridat novu polozku“ ma byt na konci kazdej urovne. Este jedna otazka, to menu tahate z databaze?

Pan Dobrman
Člen | 45
+
0
-

Výstup není úplně podle mé představy, protože mám problémy s tagem <ul>. Chápete to správně, ale pokud vyměním makro else za last, tak se text „Přidat novou položku“ vypíše 2× (s else funguje vše jak má). Menu tahám z databáze jako pole ve tvaru: ‚název‘ ⇒ ‚rodič‘, poté ho přes funkci generateTree změním na:

array(2) {
   "Menu 1" => array(2) {
      "SubMenu 1" => array(1) {
         "SubSubMenu 1" => NULL # 'název' => 'rodič'
      }
      "SubMenu 2" => NULL
   }
   "Menu 2" => NULL
}
vvoody
Člen | 910
+
0
-

Aky problem s tagom ul?

Ak pouzivate Nette/Database tak by bolo mozno lepsie riesenie z tohto vlakna.

Pan Dobrman
Člen | 45
+
0
-

Bohužel, používám Doctrine 2. Problém s tagem je, že jsem ho nejspíše špatně umístil :), takže se to pokusím přepsat a doufám, že poté už bude vše v pořádku.

kbtm
Člen | 22
+
0
-

Přeji dobrý den,

nechci zakládat nové vlákno, proto se ptám na možnost řešení stejné chyby (Maximum function nesting level of ‚100‘ reached, aborting!) …
Aplikaci (seznamuji se s některými komponentami, problém je u komponenty Menu od autora Murdej) zkouším pod několika prohlížeči – ale chyba se objeví jen pod Firefoxem – v IE, Opeře a Chrome je vše OK.
Testuji na lokálu (WinXP + WampServer).
Pokud zkusím pustit testovací aplikaci „venku“ (http://menu.nette.murdej.cz/), je vše OK i pod Firefoxem.

V prohlížeči jsou vyprázdněny všechny cache (tedy alespoň si myslím …), pokud do aplikace úmyslně zavleču nějakou chybu (třeba změním název třídy), je tato chyba správně ohlášena – tj. chybové hlášení se změní.
Chyba se neprojevovala hned zpočátku – až po několika změnách aplikace. Nyní ale zůstává stejná i při návratu k „originálu“ (modul Menu.php, na řádce 179 :

178: public function Add($node) {
179: if (is_array($node)) {
180: $newNode = new MenuNode;

S pozdravem kbtm

kbtm
Člen | 22
+
0
-

… vyřešeno … (?)

Chyba v lokálním PHP – stačilo odmazat cache prostředí WampServeru ( …\(WampServer)\tmp\ )

Server si (zřejmě) pro každý prohlížeč vytváří svoji vlastní cache/záznam session, takže chyba byla „prohlížečově“ závislá.

S pozdravem kbtm