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?
Struktura tabulek databáze:

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;
} |
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'));
} |
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'];
} |
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:
