Menu v databázi – podkategorie

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

Zdravím.
Snažím se dynamicky vykreslovat menu z databáze. V menu bych chtěl mít i podkategorie (teoreticky neomezený počet):

Sport
   Letni
      Fotbal
      Cyklo
      ...
   Zimni
      Hokej
      ....
Nářadí
   Elektrické
      Vrtačky
         Příklepové
            ...
   Manuální
      ...

Proto jsem navrhl takovouto struktutu db:

CREATE TABLE menu (
  `id` INTEGER NULL AUTO_INCREMENT DEFAULT NULL,
  `name` VARCHAR(50) NULL DEFAULT NULL,
  `up_category_id` INTEGER NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
);

Kde up_category_id odkazuje na nadřazenou kategorii.

Nyní ale nevím jak sestrojit SQL dotaz, kterým bych vypsal všechny kategorie, jejich podkategorie, jejich podkategorie…
Bude na to nějaká rekurze, nebo postupuji špatným směrem?

Díky za nakopnutí :)

Ot@s
Backer | 476
+
0
-

Na navigaci již existuje šikovná komponenta. Co se týče SQL, resp. obecně stromu, tak něco podobného se tu už řešilo. V MySQL si to budeš muset implementovat sám. Postgres má na rekurzivní dotazy přímou podporu (např. zde).

vvoody
Člen | 910
+
+1
-

Ja by som to skusil tak, ako radi dokumentacia, vkladanim bloku sameho do seba. Skusim napisat nieco z hlavy, co by sedelo na tvoj pripad:

{block #menu}
<ul>
	{foreach $menu as $item}
	<li>
		<a n:href="...">{$item->name}</a>
		{? $selection = $menu->related('menu','up_category_id')}
		{if $selection->count()>0}
			{include #menu, menu => $selection}
		{/if}
	</li>
	{/foreach}
</ul>
{/block}

Takto by si vlastne do sablony vlozil len selection korenovych poloziek menu:

$this->template->menu = $database->table('menu')->where('up_category_id',NULL);

Vo vysledku by si mala Nette Database pri prvom requeste nacachovat tie prvky menu a pri kazdom dalsom pokladat len jeden jednoduchy dotaz. Alebo lepsie asi bude cachovat cele menu.

motorcb
Člen | 552
+
+1
-

vvoody:
Dobřééééé ty :)
Jen si dovolím trošku doopravit :-) Funguje perfektně :)

{block #menu}
<ul>
    {foreach $menu as $item}
      <li>
              <a n:href="...">{$item->name}</a>
              {? $selection = $item->related('forum_category','up_category_id')}
              {if $selection->count()>0}
                      {include #menu, menu => $selection}
              {/if}
      </li>
    {/foreach}
</ul>
{/block}

Máš u mne pivo :)

iNviNho
Člen | 352
+
0
-

Neporušuje sa týmto MVC pattern? + Ak mám v databázi 200 kategorií a pre každu robiť query, nie je to spomalujúce?

Majkl578
Moderator | 1364
+
0
-

iNviNho napsal(a):

Neporušuje sa týmto MVC pattern?

Imho samotné rekurzivní vykreslování s MVC nijak nesouvisí/neodporuje.

Ak mám v databázi 200 kategorií a pre každu robiť query, nie je to spomalujúce?

Jistě, ale to je otázka optimalizace (zde zjevně nevolat related v šabloně pakliže vím, že nette\database neumí takovou věc optimalizovat/kešovat).

iNviNho
Člen | 352
+
0
-

Pretože pre človeka, ktorého to robím, tak má v DB cca 180 kategorií a na localhoste mi píše, že sa v tomto momente ⇒ http://ekotrim.sk/…kategoria/15 robí 280 queries a trvá okolo 2500 ms, čo je podla mna vela …

preto premýšlam nad iným algoritmom na vykreslovanie, resp. nahradit to query nejakou funkciou, ktorá bude pracovat s fetchnutou tabulkou kategorie a vnom vyhladavat a nie sa znova a znova dotazovat do DB …

posledný komentár vyzerá sexy = http://stackoverflow.com/…-through-php

Editoval iNviNho (14. 11. 2013 10:20)

vvoody
Člen | 910
+
0
-

Musíš robiť niečo zle, pri tom kóde z ukážky nette database nepokladá query kvôli každej kategórií.

iNviNho
Člen | 352
+
0
-

Jasné, ja som si ten select stále naplnal novým a novým querym, prerobil som to

<?php
? $select = $presenter->zistiPotomkovKategorie($item["id_kat"])}
?>

Presenter

<?php
public function zistiPotomkovKategorie($id) {
	$pole = array();

        foreach ($this->sql as $dotaz) {
            if ($dotaz->id_rodic == $id) {
                $dotaz = $dotaz->toArray();
                array_push($pole, $dotaz);
            }
        }

        return $pole;

    }
?>

a ešte pred tým v actionMetode

<?php
$sql = SelectModel::vyberVsetkyKategoriePreSelect();
$this->sql = $sql;
?>

v praxi funguje nádherne :)