Skip to content

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.

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);

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')");

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);

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);

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);

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

  1. Rychlé dotazy - celý podstrom jedním dotazem
  2. Snadné přesuny - stačí aktualizovat path tabulku
  3. Flexibilita - podporuje neomezenou hloubku
  4. 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 = ?;