Databázová struktura Menu systému
Menu systém používá pattern Closure Table pro efektivní ukládání a správu hierarchických struktur. Tento přístup umožňuje rychlé dotazy na celé stromy a snadnou manipulaci s uzly.
Přehled tabulek
1. menu - Hlavní menu
Tabulka obsahuje základní informace o menu. Obsahuje název menu, vazbu na web a id základního uzlu struktury daného menu.
| Sloupec | Typ | Popis |
|---|---|---|
| id | int(10) unsigned | Primární klíč |
| web_id | tinyint(3) unsigned | ID webu (multisite podpora) |
| name | varchar(50) | Název menu (unikátní) |
| base_node_id | int(10) unsigned | ID kořenového uzlu |
2. menu_node - Uzly menu (Closure Table)
Hlavní tabulka pro hierarchickou strukturu menu. Hlavní uzel každého menu není překládán a je pouze pro vazbu parent_id, aby se na něj dalo odkázat a přesouvat a řadit první úroveň.
| Sloupec | Typ | Popis |
|---|---|---|
| id | int(10) unsigned | Primární klíč uzlu |
| menu_id | int(10) unsigned | FK na menu.id |
| parent_id | int(10) unsigned | FK na menu_node.id (rodič) |
| order | decimal(6,1) unsigned | Pořadí mezi sourozenci (1.1, 2.1, ...) |
Cizí klíče:
- parent_id → menu_node.id (CASCADE DELETE)
- menu_id → menu.id (CASCADE DELETE)
3. menu_node_lang - Vícejazyčná data
Uchovává lokalizovaný obsah pro každý uzel. Hlavní uzel zde nemá překladové
| Sloupec | Typ | Popis |
|---|---|---|
| id | int(10) unsigned | Primární klíč |
| node_id | int(10) unsigned | FK na menu_node.id |
| lang | char(2) | Kód jazyka (cs, en, ...) |
| name | varchar(255) | Název položky v daném jazyce |
| is_hide | tinyint(1) | Příznak skrytí (0=viditelné, 1=skryté) |
| data | longtext | JSON data s dodatečnými informacemi |
Unikátní klíč: (node_id, lang)
Struktura JSON pole data:
{
"title": "Alternativní název",
"href": "/cesta/na-stranku",
"href_same": false,
"new_window": false,
"attr_class": "css-trida",
"attr_id": "css-id",
"seo_title": "SEO titulek",
"seo_keywords": "klicova, slova",
"seo_description": "SEO popis",
"text": "Obsah stránky"
}
4. menu_node_path - Closure Table (systémová)
POZOR: Tuto tabulku neupravujte ručně! Slouží pro rychlé dotazy na hierarchii.
| Sloupec | Typ | Popis |
|---|---|---|
| ancestor_id | int(10) unsigned | ID předka |
| descendant_id | int(10) unsigned | ID potomka |
| path_length | int(10) unsigned | Vzdálenost (0 = sám sobě) |
Primární klíč: (ancestor_id, descendant_id)
Databázové procedury
Možno je volat i ve správci AdminNeo.
menu_add_node(node_new_id, node_parent_id)
Automaticky aktualizuje closure table při přidání nového uzlu.
Parametry:
- node_new_id - ID nově vytvořeného uzlu
- node_parent_id - ID rodiče
Použití:
CALL menu_add_node(123, 45);
menu_get_tree(node_id, lang_code)
Načte kompletní strom menu pod daným uzlem pro konkrétní jazyk. Využívá se hlavně na frontendu, kdy vrací strom menu včetně úrovní a id uzlů pro drobečkovou navigaci.
Pozor: Vrací pouze uzly, které jsou aktuálně viditelné (is_hide = 0).
Parametry:
- node_id - ID kořenového uzlu
- lang_code - kód jazyka ('cs', 'en', ...)
Vrací:
- id - ID uzlu
- parent_id - ID rodiče
- name - název v daném jazyce
- formatted_name - název s odsazením (----Podpoložka)
- level - úroveň zanoření (0, 1, 2, ...)
- order - pořadí
- breadcrumbs - čárkou oddělené ID předků
Použití:
CALL menu_get_tree(1, 'cs');
DB::results("CALL menu_get_tree(1, 'cs')");
menu_get_tree_all(node_id)
Načte celý strom včetně všech jazykových variant. Toto se využívá v administraci.
Pozor: Pro velké menu e-shopu bude třeba doupravit, aby se nevracely všechny JSON položky pole data. SEO texty mohou být obsahově veliké.
Parametry:
- node_id - ID kořenového uzlu
Použití:
CALL menu_get_tree_all(1);
menu_move_node(node_old_parent_id, node_new_parent_id)
Přesune uzel na nové místo v hierarchii.
Parametry: - node_old_parent_id - ID starého rodiče - node_new_parent_id - ID nového rodiče
Použití:
CALL menu_move_node(45, 67);
menu_reorder_siblings(parent_id)
Přeřadí sourozence pod stejným rodičem (vyčistí mezery v číslování).
Parametry:
- parent_id - ID rodiče
Použití:
CALL menu_reorder_siblings(45);
menu_set_visibility(node_id, lang_code, hide_status)
Nastaví viditelnost uzlu a všech jeho potomků v daném jazyce.
Parametry:
- node_id - ID uzlu
- lang_code - kód jazyka
- hide_status - 0 (viditelné) nebo 1 (skryté)
Použití:
CALL menu_set_visibility(45, 'cs', 1);
Výhody Closure Table
- Rychlé dotazy - celý podstrom jedním dotazem
- Snadné přesuny - stačí aktualizovat path tabulku
- Flexibilita - podporuje neomezenou hloubku
- Integrita - CASCADE DELETE automaticky čistí data
Příklady dotazů
Načtení přímých potomků
SELECT n.*, l.name
FROM menu_node n
JOIN menu_node_lang l ON n.id = l.node_id
WHERE n.parent_id = ? AND l.lang = 'cs'
ORDER BY n.order;
Načtení cesty k uzlu (breadcrumbs)
SELECT l.name
FROM menu_node_path p
JOIN menu_node_lang l ON p.ancestor_id = l.node_id
WHERE p.descendant_id = ? AND l.lang = 'cs'
ORDER BY p.path_length DESC;
Počet potomků uzlu
SELECT COUNT(*) - 1 as children_count
FROM menu_node_path
WHERE ancestor_id = ?;