Generování vícejazyčného formuláře v NETTE

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

* – 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:

Napsat komentář

Vaše emailová adresa nebude zveřejněna.

Tato stránka používá Akismet k omezení spamu. Podívejte se, jak vaše data z komentářů zpracováváme..