Občas je potřeba mít vícejazyčnou strukturu menu (kategorií, …) s tím, že předem nevím kolik jazyků budu potřebovat, ale zároveň chci aby administrace s tím počítala.
Jak takový automaticky generovaný formulář napsat v NETTE?
Presenter (továrnička na generování formuláře):
public function createComponentCat() { // vytáhneme si všechny jazyky $langs = dibi::fetchAll('SELECT [id], [code] FROM [languages] ORDER BY [code]'); $form = new AppForm; // * (budu se na toto místo dále odkazovat v textu) foreach ($langs as $lang) { $form->addText("name_{$lang['id']}", "Jméno kategorie [{$lang['code']}]:") ->addRule(Form::FILLED); } // * // tyto skryté pole se budou hodit pro editaci $form->addHidden('id'); $form->addHidden('parent_id'); $form->addSubmit('send', ' Uložit '); $form->onSubmit[] = array($this, 'formCatSubmitted'); return $form; } |
* – tady mohou pro více polí nastat dvě situace:
1/ chceme jazykově oddělené atributy mít u sebe
Pak musíme pro každý atribut vložit tento cyklus. Takže pět atributů znamená pět pod sebou těchto cyklů.
2/ chceme atributy seskupovat podle jazyků
V tomto případě nám stačí jeden cyklus a v něm nasázené všechny atributy.
O výkonu zde nemá cenu se dohadovat. Jedná se o administraci a tam nikdy nebude velký nával.
Presenter (zpracování formuláře):
public function formCatSubmitted($form) { $val = $form->getValues(); # TABLE: categories $categories['id'] = $val['id']; $categories['parent_id'] = $val['parent_id']; if ($categories['id'] == 0) { // jedná se o nový záznam // vytáhneme si level vkládaného záznamu // level je hloubka zanoření ve stromové struktuře $categories['level'] = ($categories['parent_id'] == 0) ? 1 : dibi::fetchSingle('SELECT [level]+1 FROM [categories] WHERE [id]=%i LIMIT 1', $categories['parent_id']); // vytáhneme si position vkládaného záznamu (u nového záznamu budeme vkládat novou kategorii až na konec) // position je pořadí v dané kategorii $categories['position'] = dibi::fetchSingle('SELECT [position]+1 FROM [categories] WHERE [parent_id]=%i ORDER BY [position] DESC LIMIT 1', $categories['parent_id']); // oprava při nule pokud vkládáme první záznam $categories['position'] = ($categories['position'] == 0) ? 1 : $categories['position']; dibi::query('INSERT INTO [categories]', $categories); $categories_translations['categories_id'] = dibi::insertId(); } else { dibi::query('UPDATE [categories] SET', $categories, 'WHERE [id]=%i LIMIT 1', $categories['id']); $categories_translations['categories_id'] = $categories['id']; } # TABLE: categories_translations $langs = dibi::fetchAll('SELECT [id] FROM [languages]'); if ($categories['id'] == 0) { // jedná se o nový záznam foreach ($langs as $lang) { $categories_translations['language_id'] = $lang['id']; $categories_translations['name'] = $val["name_{$lang['id']}"]; dibi::query('INSERT INTO [categories_translations]', $categories_translations); } } else { $categories_id = $categories_translations['categories_id']; unset($categories_translations['categories_id']); foreach ($langs as $lang) { $categories_translations['name'] = $val["name_{$lang['id']}"]; dibi::query('UPDATE [categories_translations] SET', $categories_translations, 'WHERE [language_id] = %i AND [categories_id] = %i LIMIT 1', $lang['id'], $categories_id); // tady je ještě třeba vyřešit situaci, kdy již máme naplněnou databázi kategoriemi a přidáme nový záznam do tabulky jazyků. Update by nebylo nad čím provést, proto musíme nové záznamy pro nové jazyky INSERTnout do tabulky překladů. // zjistíme si, zda nám update něco ovlivnil (ANO - záznam existuje, NE - jedná se o nový záznam) $info = dibi::getConnection()->driver->getInfo(); if ($info['Rows matched'] === 0) { $categories_translations['language_id'] = $lang['id']; $categories_translations['categories_id'] = $categories_id; dibi::query('INSERT INTO [categories_translations]', $categories_translations); } } } $this->flashMessage('Data uložena.', 'info'); $this->redirect('Category:default', $this->getParam('parent_id')); } |
A teď už jen pro pořádek zbývá uvést metody presenteru Add a Edit:
public function renderAdd($parent_id) { $this['cat']->setDefaults(array('id' => 0, 'parent_id' => $parent_id)); $this->template->form = $this['cat']; } public function renderEdit($id, $parent_id) { $this->setView('add'); // vytáhneme si data $rows = dibi::fetchAll('SELECT *, [b].[id] AS [bid] FROM [categories_translations] [a] JOIN [categories] [b] ON [a].[categories_id] = [b].[id] WHERE [b].[id] = %i ORDER BY [language_id]', $id); // začneme generovat pole pro naplnění formuláře pro editaci $arr = array(); foreach ($rows as $row) { $arr["name_{$row['language_id']}"] = $row['name']; } $arr['id'] = $row['bid']; $arr['parent_id'] = $row['parent_id']; $this['cat']->setDefaults($arr); $this->template->form = $this['cat']; } |
Výsledek takového formuláře pak vypadá pro tři jazyky a více polí třeba takto: