Menu a Submenu cez Databázu
- SontoEremo
- Člen | 341
Zdravím ľudia…
Prosím Vás máme záujem o menu ktoré by sa ťahalo aj so submenami
z databáze.
Skúšal som poriešiť niečo takéto
menu.latte
<ul>
{foreach $menus as $mymenu}
{? $sub_relatedes = $mymenu->related('submenu', 'id')}
{if $sub_relatedes->count('*')>0}
<li><a href="#">{$mymenu->title}</a>
<ul>
<li>
<a href="{$mymenu->ref('submenu', 'id')->sublink}">
{$mymenu->ref('submenu', 'id')->subtitle}
</a>
</li>
</ul>
</li>
{? $my_relateds = $mymenu->related('menu1', 'id')}
{elseif $my_relateds->count('*')>0}
<li><a n:href="$mymenu->link">{$mymenu->title}</a></li>
{/if}
{/foreach}
</ul>
Presenter
public function renderDefault()
{
$this->template->menus = $this->menu1->findAll();
}
MenuRepository
/** @var Nette\Database\Connection */
private $database;
public function __construct(Nette\Database\Connection $database)
{
$this->database = $database;
}
public function findAll()
{
return $this->database->table('menu1');
}
public function findById($id)
{
return $this->findAll()->get($id);
}
public function insert($values)
{
return $this->findAll()->insert($values);
}
A nakoniec DB
CREATE TABLE IF NOT EXISTS `menu1` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`submenu_id` int(11) unsigned NOT NULL,
`title` varchar(64) NOT NULL,
`link` varchar(60) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;
--
-- Sťahujem dáta pre tabuľku `menu1`
--
INSERT INTO `menu1` (`id`, `submenu_id`, `title`, `link`) VALUES
(1, 1, 'Menu1', 'Index:default'),
(2, 2, 'Menu2', 'Index:default'),
(3, 0, 'Menu3', 'Index:default'),
(4, 0, 'Menu4', 'Index:default'),
(5, 3, 'Menu5', 'Index:default');
-- --------------------------------------------------------
--
-- Štruktúra tabuľky pre tabuľku `submenu`
--
CREATE TABLE IF NOT EXISTS `submenu` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`subtitle` varchar(64) NOT NULL,
`sublink` varchar(60) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
--
-- Sťahujem dáta pre tabuľku `submenu`
--
INSERT INTO `submenu` (`id`, `subtitle`, `sublink`) VALUES
(1, 'Submenu1', 'Index:default'),
(2, 'Submenu5', 'Index:default'),
(3, 'Submenu3', 'Index:default');
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
Na moje počudovanie mi zobrazuje menu aj submenu lenže problém nastáva ak mám toto v tabuľke
Tabuľka Menu Tabuľka Submenu
--------------------------------------------------------------------------------
id submenu_id title link | id subtitle sublink
--------------------------------------------------------------------------------
1 1 Menu1 Index:default | 1 Submenu1 Index:default
2 2 Menu2 Index:default | 2 Submenu5 Index:default
3 0 Menu3 Index:default | 3 Submenu3 Index:default
4 0 Menu4 Index:default |
5 3 Menu5 Index:default |
--------------------------------------------------------------------------------
v poriadku zobrazí poradie Menu1+Submenu1
Menu2+Submenu5
Ale po pridaní viac menu a submenu a ich následne premiešanie už nezobrazí
poradie Menu3, Menu4, Menu5+Submenu3 ale preskočí to všetko
a zobrazuje ich
v tomto poradí Menu1+Submenu1,Menu2+Submenu5,Menu3+Submenu3, Menu4,
Menu5 a pritom Menu5 má určené
Submenu3
Hádam som to dostatočne vysvetlil :)
Viem, že toto nieje 100% ideálne riešenie no po prebádaní tu na fóre a
v dokumentácii zomňa proste nevyšlo dosť !určite! jednoduchšie riešenie.
Prosím ak sa Vám bude chcieť mohli by ste sem dať nejaké rozumnejšie
príklady ktoré nielen pomôžu mňe ale mnohím začiatočnikom.
Ešte ma trápi jedna vec a to ako vytvoriť formulár ktorý bude
vložievať menu do menu1 a submenu do submenu a určovať ktoré sub patri pod
ktoré menu a naopak ktoré menu nebude obsahovať sub … Fúha sam
som sa v tom teraz dosť zaplietol :) …
Ale to by sa asi riešilo cez select
ďakujem vopred všetkym.
- Petr Hudík
- Člen | 49
Ahoj, pročítal jsem Tvůj příspěvek několikrát a mám trochu zmatek už v samotné struktuře dat. Proč jsi zvolil právě tento způsob? Dle mého názoru je zvolený způsob nevhodný, protože předpokládá jednu úroveň zanoření a zadání na strukturu menu se může velice snadno změnit, proto je často výhodnější vytvořit pro menu obecnější strukturu.
Domnívám se, že problém, který řešíš se jmenuje ukládání stromové struktury dat. Něco nalezneš v prastarém článku na Intervalu, problému se věnuje i Jakub Vrána v Traverzování kolem stromu a mnoho dalších příspěvků. Další zdroje jistě snadno nalezneš.
Editoval Petr Hudík (12. 5. 2013 11:45)
- SontoEremo
- Člen | 341
Noo to som aj ja sám s toho bol oblbnutý :)
Prešiel som si tvoje odkazy ale stále mi nieje jasne ako teda na tu db
štruktúru a ako to celé vlastne pospájať nemohol by si v jednoduchosti
hodiť nejaký kód robený v Nette a NDB? ďakujem.
- Petr Hudík
- Člen | 49
Prosím pokus se sám sobě odpovědět na následující otázku – „Co je tvým cílem – snažíš se vytvořit webovky, nebo se naučit Nette?“ Pokud pouze první bude pro Tebe daleko výhodnější (a domnívám se i levnější), pokud si seženeš někoho, kdo to naprogramuje. Pokud je Tvým cílem se něco naučit, není řešení, abychom sem házely zdrojáky a Ty jsi lepil kód pomocí metody CTRL+C/CTRL+V, prosím oprav mě, pokud se pletu.
Pro začátek navrhuji úplně tu nejjednodušší stromovou strukturu.
U každého záznamu pouze přidat ID rodiče. Záznamy, které jsou na
nejvyšší úrovni menu, mohou mít ID rodiče NULL
.
- SontoEremo
- Člen | 341
Nazdar Petr Hudík
Bohužial sa naozaj pletieš :)
Nette sa chcem naučiť a nie som typ človeka ktorý spravý copy/paste a jede
se dál :)
Mne hlavne išlo o to ako na to v nette aké príkazy použiť a ako na
tabuľku …
čo som včera do pol 4 rána kukal všetko okolo ukladania stromovej
štruktúry a traverzovanie okolo stromu
mi prišlo nejasné napr.
tabuľka všetko je v nej natlačené? id → nazov
→ link → sub
fakt mi ide iba o to ako to vyzerá v nette.
- vvoody
- Člen | 910
Nette nerieši menu, nette za teba nerieši ani ukladanie stromovej
štruktúry, nette čiastočne rieši až väzby/FK medzi tabuľkami/entitami.
Návrh databáze je preto tvoja starosť s ktorou ti nette nepomôže, treba si
prejsť nejaké základy relačných databáz miesto hľadania „univerzálneho
riešenia na menu“ v nette.
Keď budeš mať vhodne navrhnutú databázu pre stromové menu, nette ti
pomôže z databáze to menu načítať, pomôže ti menu zobraziť, pomôže
ti z toho všetkého spraviť jednoducho znovupoužiteľnú komponentu,
prípadne ti umožní menu jednoducho cachovať atď. Ale až budeš sám mať
jasno s akými dátami pracuješ.
Áno, všetko môže byt natlačené v jednej tabuľke.
- id
- title
- link/destination
- parent_id (FK na id tejto istej tabuľky, NULLable)
Editoval vvoody (13. 5. 2013 12:45)
- SontoEremo
- Člen | 341
Nazdar vvoody
Ak som správne pochopil tak strom tabuľky je nasledovný:
-----------------------------------
Tabuľka menu
-----------------------------------
id | title | link | parent_id |
1 | menu1 | link:link| NULL |
2 | menu2 | link:link| NULL |
3 | sub1 | link:link| 1 |
-----------------------------------
-----------------------------------
takže ak je menu1->id(1) a sub1->parent_id(1)
znamená, že menu1 bude obsahovať sub1 pretože parent_id ma id menu1 ?
a naopak ak menu1 je NULL znamená, že neobsahuje žiadne submenu.
- Petr Hudík
- Člen | 49
@SontoEremo: ano, je to přesně tak, jak píšeš.
Dobré ještě je, když sloupec parent_id
obsahuje cizí klíč
k sloupci id
.
Nyní, když budeš chtít vypsat menu nejvyšší úrovně (menu1, menu2),
tak stačí vypsat všechny, kde parent_id
je NULL, tím bych
pravděpodobně začal…
- SontoEremo
- Člen | 341
@Petr Hudík:
To som sa ešte chcel spýtať ako nastaviť parent_id cudzí kľúč ?
Všade kde som pozeral bolo v phpmyadmine v typ: FOREIGN KEY
lenže to ani za boha neviem nájsť
mám tam všetko:
INT
TINYINT
MEDIUMINT
atď…
FOREIGN KEY nikde
- Petr Hudík
- Člen | 49
Bohužel nedokážu poradit, používám Adminer, který velice doporučuji, v něm to nastavíš opravdu snadno.
Pouze doplním, že oba sloupce musí být stejného datového typu.
- MartinitCZ
- Člen | 580
@**Glottis**: Však to je dobře. Tohle je o neznalosti SQL a né o problémech s Nette. Toto má být na jpw.cz
- SontoEremo
- Člen | 341
OK OK ospravedlňujem sa …
posledný príspevok sa môže zmazať…
Nevedel som, že otázka ohľadom DB je mimo
Sorry :)
Do budúcna sa poučím!
- SontoEremo
- Člen | 341
Takže snažil som sa niečo poskladať no je to nejaké nestabilné a čudné :)
CREATE TABLE IF NOT EXISTS `menu` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`link` varchar(255) NOT NULL,
`parent_id` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;
--
-- Sťahujem dáta pre tabuľku `menu`
--
INSERT INTO `menu` (`id`, `title`, `link`, `parent_id`) VALUES
(1, 'Dashboard', 'Index:default', NULL),
(2, 'Menu', 'Index:default', NULL),
(3, 'Submenu', 'Index:default', 1);
--
-- Obmedzenie pre exportované tabuľky
--
--
-- Obmedzenie pre tabuľku `menu`
--
ALTER TABLE `menu`
ADD CONSTRAINT `menu_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `menu` (`id`);
Presenter
public function renderDefault()
{
$this->template->menus = $this->database->table('menu')
->where('id')
->order('parent_id');
}
Šablóna
<ul>
{foreach $menus as $menu}
<li>{$menu->title}
{if $menu->parent_id > 0}
<ul>
<li>{$menu->title}</li>
</ul>
{/if}
</li>
{/foreach}
</ul>
Menu mi ukáže ale submenu ktoré má byť pod Dashboard nie je ale výsledok je nasledovný:
Dashboard
Menu
Submenu
Submenu
Som už z toho na totálku úplne prevrátený mohli by ste ma ešte trocha
popostrčiť?
ďakujem vopred všetkym.
- Tabetha
- Člen | 140
Takto by to malo fungovať…
$this->template->menus = $this->database->table('menu2')
->where("parent_id IS NULL" )
->order('parent_id');
<ul>
{foreach $menus as $menu}
{var $childs = $menu->related('menu2','parent_id')}
{dump $childs->count()}
<li>{$menu->title}
{if $childs->count() > 0}
<ul>
{foreach $childs as $child}
<li>{$child->title}</li>
{/foreach}
</ul>
{/if}
</li>
{/foreach}
</ul>
a výsledok (doplnil som tam riadky kvôli overeniu)
<ul>
<li>Dashboard
<ul>
<li>Submenu</li>
<li>Test5</li>
</ul>
</li>
<li>Menu
<ul>
<li>Test4</li>
</ul>
</li>
</ul>
- SontoEremo
- Člen | 341
Tabetha
Tak teraz som sa zasmial k smrti aký som hlúpi Veľmi pekne ti ďakujem
zas mi toto fórum a ochotný členovia pomohli :)
Takže prikladám sem Menu a Submenu ťahané z DB
Presenter:
/** @var Nette\Database\Connection */
private $database;
public function __construct(Nette\Database\Connection $database)
{
$this->database = $database;
}
public function renderDefault()
{
$this->template->menus = $this->database->table('menu')
->where("parent_id IS NULL" )
->order('parent_id');
}
Šablóna:
<ul>
{foreach $menus as $menu}
{var $childs = $menu->related('menu','parent_id')}
{dump $childs->count()}
<li>
{if $childs->count() > 0}
<a href="javascript:;">{$menu->title}</a>
{else}
<a n:href="$menu->link">{$menu->title}</a>
{/if}
{if $childs->count() > 0}
<ul>
{foreach $childs as $child}
<li><a n:href="$child->link">{$child->title}</a></li>
{/foreach}
</ul>
{/if}
</li>
{/foreach}
</ul>
Ešta aby som nezabudol mám tam tento kód
{if $childs->count() > 0}
<a href="javascript:;">{$menu->title}</a>
{else}
<a n:href="$menu->link">{$menu->title}</a>
{/if}
A to len preto lebo moja šablóna vyžaduje v menu ktoré ma submenu aby
bol href=„javascript:;“
Normálne to má byť
<ul>
{foreach $menus as $menu}
{var $childs = $menu->related('menu','parent_id')}
{dump $childs->count()}
<li>
<a n:href="$menu->link">{$menu->title}</a>
{if $childs->count() > 0}
<ul>
{foreach $childs as $child}
<li><a n:href="$child->link">{$child->title}</a></li>
{/foreach}
</ul>
{/if}
</li>
{/foreach}
</ul>
a Tabuľka DB:
CREATE TABLE IF NOT EXISTS `menu` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`link` varchar(255) NOT NULL,
`parent_id` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=8 ;
--
-- Sťahujem dáta pre tabuľku `menu`
--
INSERT INTO `menu` (`id`, `title`, `link`, `parent_id`) VALUES
(1, 'Menu1', 'Index:default', NULL),
(2, 'Menu2', 'Index:default', NULL),
(3, 'Submenu1', 'Index:default', 1),
(4, 'Submenu2', 'Index:default', 1),
(5, 'Menu3', 'Index:default', NULL),
(6, 'Menu5', 'Index:default', NULL),
(7, 'Sumnenu3', 'Index:default', 6);
--
-- Obmedzenie pre exportované tabuľky
--
--
-- Obmedzenie pre tabuľku `menu`
--
ALTER TABLE `menu`
ADD CONSTRAINT `menu_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `menu` (`id`);
Ešte raz všetkým veľmi pekne ďakujem..........
- Tabetha
- Člen | 140
Ešte to môžeš upraviť takto ak sa nemýlim… a dump môžeš dať preč :-) ak ho nepotrebuješ
<ul>
{foreach $menus as $menu}
{var $childs = $menu->related('menu','parent_id')}
<li>
{if $childs->count() > 0}
<a href="javascript:;">{$menu->title}</a>
<ul>
{foreach $childs as $child}
<li><a n:href="$child->link">{$child->title}</a></li>
{/foreach}
</ul>
{else}
<a n:href="$menu->link">{$menu->title}</a>
{/if}
</li>
{/foreach}
</ul>
- SontoEremo
- Člen | 341
@Tabetha:
Mám to takto
<ul>
{foreach $menus as $menu}
{var $childs = $menu->related('webadmin_menu','parent_id')}
{if $childs->count('*') > 0}
<li class="has-sub {foreach $childs as $child}{ifCurrent $child->menu_link}active{/ifCurrent}{/foreach}">
<a href="javascript:;">
<i class="{$menu->menu_icon}"></i>
<span class="title">{$menu->menu_title}</span>
<span class="arrow "></span>
</a>
<ul class="sub">
{foreach $childs as $child}
<li class="{ifCurrent $child->menu_link}active{/ifCurrent}">
<a n:href="$child->menu_link">{$child->menu_title}</a>
</li>
{/foreach}
</ul>
</li>
{else}
<li class="{ifCurrent $menu->menu_link}active{/ifCurrent}">
<a n:href="$menu->menu_link">
<i class="{$menu->menu_icon}"></i>
<span class="title">{$menu->menu_title}</span>
<span class="selected"></span>
</a>
</li>
{/if}
{/foreach}
</ul>
Teraz sa práve snažím rozbehnuť breadcrumb
<ul class="breadcrumb">
{if $user->isLoggedIn()}
{foreach $menus as $breadcrumbmenu}
<li>
<i class="{$breadcrumbmenu->menu_icon}"></i>
<a href="{$breadcrumbmenu->menu_link}">{$breadcrumbmenu->menu_title}</a>
<i class="icon-angle-right"></i>
</li>
{/foreach}
{/if}
</ul>
Myslíš, že môže použiť rovnakú metodu ak s menu?
{var $childs = $menu->related('webadmin_menu','parent_id')}
{if $childs->count('*') > 0}
{foreach $childs as $child}
{/foreach} atď...