Jak na rekurzi v šabloně aneb jak vykreslit rodokmen?

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

Zdravím,
aktuálně jsem narazil na problém s vykreslením rodokmenu v šabloně.

Rodokmen mám aktuálně řešen čistě v PHP (z dávných časů) a teď ho chci překlopit do Nette. Princip generování rodokmenu mám následující:

function rodokmen ($zvire,$hloubka) {

	// zde se provede dotaz na načtení údajů a rodičů pro $zvire z DB

	//data se nacetli z DB jdeme na to je zpracovat
	while ($Vysledek = $stmt->fetch()) {

		// zde se provede vykreslení údajů zvířete (jako jedna položka v rodokmenu) a probíhá práce s promenou $hloubka

		//tady je rekurze!
    	rodokmen ($Vysledek['matka'],$hloubka);
        rodokmen ($Vysledek['otec'],$hloubka);
    }
}

Uvedený princip bych tedy potřeboval překlopit do Nette, ale nevím jak modelovou metodu průběžně vykreslovat přes presenter do šablony.

Nevíte někdo jak na to prosím? Díky moc

Editoval Croc (25. 10. 2015 8:53)

Azathoth
Člen | 495
+
0
-

já když jsem potřeboval vykreslovat strom, tak jsem měl komponentu na vykreslení jednoho vrcholu a v cyklu jsem pak vypsal komponentu pro každého potomka.
Takže komponenta Node má v sobě tohle latte

<li>
	{*dome data about node*}

	<ul n:if="count($descendants) > 0">
		{foreach $descendants as $descendant}
			{control node-$descendant->id}
		{/foreach}
	</ul>
</li>

a v ta komponenta tedy, jak vidíš, dostane ID toho vrcholu, podle toho má vrchol, který má vypsat a v proměnné descendants má všechny potomky toho vrcholu.
Takže z modelu se vytáhne vždycky vrchol + jeho potomci. A takhle se to provede pro každý vrchol stromu.

Editoval Azathoth (25. 10. 2015 10:23)

duskohu
Člen | 778
+
0
-

Trosku stare, ale na priklad staci:
https://forum.nette.org/…icia-funkcie#…

Croc
Člen | 270
+
0
-

Díky moc za příklady, zkusím to z toho dát dohromady. Mám jen jeden dotaz. Uvedené příklady ale vycházejí z toho, že se pracuje pouze s jedním polem, které obsahuje celý strom, je tomu tak nebo se pletu?

duskohu
Člen | 778
+
0
-

Priklad od @Azathoth je rekurzia ktora sa vola, Priklad od @nanuqcz pouziva strom

Croc
Člen | 270
+
0
-

Nevím jestli dělám něco špatně, ale nějak se mi to nedaří rozchodit.

Mám vytvořenou komponentu:

EDIT:
INodeFactory.php

namespace App\Components;

interface INodeFactory
{
    /**
     * @return NodeControl
     */
    public function create();
}

NodeControl.php

namespace App\Components;

use Nette\Application\UI\Control;

class NodeControl extends Control
{
    /** @var \Nette\Database\Context */
    private $database;

    /** @var \App\Repository\AnimalRepository */
    protected $animalRepository;

    private $parents;
    private $animal;

    public function __construct(\App\Repository\AnimalRepository $animalRepository) {
        parent::__construct();
        $this->animalRepository = $animalRepository;
    }

    protected function createComponentNode()
    {   $animalRepository = $this->animalRepository;
        $node = new Components\NodeControl($animalRepository);
        return $node;
    }

    public function render($id)
    {
        $template = $this->template;
        $template->setFile(__DIR__ . '/NodeControl.latte');

        $this->template->animal = $this->animalRepository->getAnimal($id);
        $this->template->parents = $this->animalRepository->getAnimalParents($id);

        $template->render();
    }
}

NodeControl.latte

{block node}

{foreach $parents as $parent}
	{if $hloubka <> 5} //vykreslení části tabulky dle její hloubky
		{if $hloubka == 4} <tr><td rowspan="8"> {/if}
		{if $hloubka == 3} <td rowspan="4"> {/if}
		{if $hloubka == 2} <td rowspan="2"> {/if}
		{if $hloubka == 1} <td> {/if}

		{if $hloubka > 0}
			{$animal->name} </td> //jméno zvířete
		{/if}
	{/if}

	{if $hloubka == 1} </tr> {/if}

	{if $hloubka <= 0}
		{php return}
    {else}
		{php $hloubka--}

        {control node, $parent->id_father, $hloubka}
        {control node, $parent->id_mother, $hloubka}
    {/if}
{/foreach}

{/block}

V šabloně kde chci strom vykreslit mám toto:

{block content}
	{control node, $animal->id_animal}
{/block}

Problém je, že mi Tracy hlásí chybu Component with name 'node' does not exist. v šablone NodeControl.latte právě při volání rekurze.

Nevíte prosím co tam mám špatně?

Editoval Croc (25. 10. 2015 22:35)

Šaman
Člen | 2640
+
0
-

Vždyť v kódu komponenty opravdu žádnou továrnu na komponentu Node nemáš (createComponentNode()).

Jinak já jsem tohle řešil v šabloně bez komponenty, jen jsem includoval latte blok. A jako parametr dostal celý objekt uzel, nikoliv jeho id. Pro větší stromy to bude i citelně efektivnější, než pro každý uzel znovu sahat do repozitáře.

Azathoth
Člen | 495
+
0
-

podle mne to bude stejně efektivní, pokud používáš Doctrine nebo máš nějaké jiné cache, abys to mohl tahat z paměti. A nebo eager load, co ti načte do paměti celý strom, když víš, že ho potřebuješ, a model servíruje jen postupně jeho kusy.

Croc
Člen | 270
+
0
-

@Šaman Díky, měl si pravdu :)

@Azathoth Doctrine nepoužívám, takže to musím načítat z DB po jednom. Třeba časem k tomu dojde :)

Ještě potřebuju vyřešit jednu drobnost a tou je hloubka vykreslení rodokmenu jako vstupní parametr. Logiku vykreslení jsem použil z předchozího webu (non-Nette) a při každé rekurzi předávám parametr $hloubka (aby to nevykreslovalo do nekonečna). Problém mám v tom, že se mi při rekurzi nedaří ten parametr předat… V postu výše jsem doplnil aktuální stav.

Azathoth
Člen | 495
+
0
-

@Croc tak doporučuji si udělat v modelu nějakou drobnou mezivrstvu, která si v sobě bude držet všechny načtené entity a jejich Id. A pokud bys chtěl nějakou entitu načíst z databáze podle Id, tak se model koukne, jestli už není načtená a pokud je, tak ti ji vrátí.

Croc
Člen | 270
+
0
-

Vyřešeno, nakonec jsem měl chybu v datech, rodokmen se mi tedy již vykresluje

@Azathoth Určitě to je lepší řešení jak říkáš. Udělám ještě výkonnostní testy, ale asi to zatím nechám takto. Mám toho ještě dost před sebou co musím řešit takže se k tomu určitě někdy vrátím :)

Díky tedy všem za rady.

Editoval Croc (25. 10. 2015 23:27)