Formulář pro administraci vícejazyčného obsahu
- kuba1999
- Člen | 13
Zdravím.
Potřebuji udělat, aby se mi do vytvořeného formuláře automaticky přidaly zklonované formulářové komponenty pro ostatní jazykové mutace.
Tedy udělat z formuláře:
Název: _____
Obsah: _____
...
Tento formulář:
Název: _____
Název (en): _____
Název (de): _____
Obsah: _____
Obsah (en): _____
Obsah (de): _____
...
Neměl by někdo nápad, jak toto zařídit? Aktuálně mám udělanou
komponentu, která toto zařídí, ale mám problém klonování komponent
formuláře. Chtěl bych komponenty formuláře několikrát naklonovat a
původní „zachodit“ – ale skončí to s výjimkou
Component 'title' is not attached to 'Nette\Forms\Form'.
.
public function createComponentForm()
{
$groups = $this->form->getGroups();
foreach($this->form->getGroups() as $group)
{
$this->form->removeGroup($group);
}
foreach($groups as $group)
{
foreach($group->getControls() AS $control)
{
$container = $this->form->addContainer($control->name);
$container->setCurrentGroup($group);
foreach(self::$locales AS $locale)
{
if($locale != "cs")
{
$cloneControl = clone $control;
$cloneControl->caption .= " [".$locale."]";
$container->addComponent($cloneControl, $locale);
}
else
$container->addComponent(clone $control, "cs"); // Nefunguje
//$container->addComponent($control, "cs"); // OK
}
}
}
return $this->form;
}
Když použiji původní komponentu formuláře, kód:
if($locale != "cs")
{
$cloneControl = clone $control;
$cloneControl->caption .= " [".$locale."]";
$cloneControl->addClass($locale);
$container->addComponent($cloneControl, $locale);
}
else
//$container->addComponent(clone $control, "cs"); // Nefunguje
$container->addComponent($control, "cs"); // OK
Tak výsledný kód není to, co bych si představoval – zklonované prvky mají zděděné nějaké vlastnosti z původního – tzn.:
- když přidám prvku například třídu class=„$locale“, tak se mi to projeví i na ostatních prvcích
<tr class="required">
<th><label class="required" for="frm-addEditForm-form-content-cs">Obsah</label></th>
<td><textarea name="content[cs]" class="de en CKeditor" id="frm-addEditForm-form-content-cs" required data-nette-rules='[{"op":":filled","msg":"Položka je povinná"}]'></textarea></td>
</tr>
<tr class="required">
<th><label class="required" for="frm-addEditForm-form-content-cs">Obsah [en]</label></th>
<td><textarea name="content[en]" class="de en CKeditor" id="frm-addEditForm-form-content-cs" required data-nette-rules='[{"op":":filled","msg":"Položka je povinná"}]'></textarea></td>
</tr>
<tr class="required">
<th><label class="required" for="frm-addEditForm-form-content-cs">Obsah [de]</label></th>
<td><textarea name="content[de]" class="de en CKeditor" id="frm-addEditForm-form-content-cs" required data-nette-rules='[{"op":":filled","msg":"Položka je povinná"}]'></textarea></td>
</tr>
Děkuji za reakce.
- Oli
- Člen | 1215
Asi to uplně přesně nechápu, ale buď bych zkusil replicator. Nebo si udělal továrničku, která by vytvářela formulář a hodil ji do multiplieru
- kuba1999
- Člen | 13
Oli napsal(a):
Asi to uplně přesně nechápu, ale buď bych zkusil replicator. Nebo si udělal továrničku, která by vytvářela formulář a hodil ji do multiplieru
Jednoduše napsáno:
Jde mi o to, abych komponentě předal formulář a ta mi z něho udělala
vícejazyčný formulář. Takže abych nemusel ručně veškerým formulářům
v administraci vytvářet prvky pro všechny mutace ručně. Když by
v budoucnu přibyla další mutace, nemusel bych upravovat všechny
formuláře.
Na replikátor se ještě jednou podívám. Ale když jsem na něj narazil, tak jsem myslel, že to není co potřebuji.
Editoval kuba1999 (8. 9. 2014 13:04)
- Jan Suchánek
- Člen | 404
@kuba1999: A nebude lepší to té komponentě předávat, těch polí pro překlad bude málo ne? Nakonec bys to mohl mít i v configu.
- Oli
- Člen | 1215
kuba1999 napsal(a):
Když by v budoucnu přibyla další mutace, nemusel bych upravovat všechny formuláře.
S tím počítají obě moje řešení. Pokud by jsi měl továrničku na nějakou komponentu, která by zajišťovala vykreslední toho formuláře, tak pak v multiplieru se ti vytvoří pokaždé nová instance. Takže to potom může vypadat zhruba takto:
return new \Nette\Application\UI\Multiplier(function($lang) {
return $this->formular->create()->setLang($lang);
});
Potom by jsi mohl přidat další jazyk prostě tím, že $lang bude obsahovat další hodnotu.
Na replikátor se ještě jendou podívám. Ale když jsem na něj narazil, tak jsem myslel, že to není co potřebuji.
Když jsem se s ním poprvé setkal, tak jsem si to myslel taky. Dělá přesně to, že nějakou část formuláře vytvoří několikrát.
- Jiří Nápravník
- Člen | 710
Nevím, jestli úplně chápu, ale šel bych na to tak, že si předám seznam všech těch jazyků, předám té továrně na tvorbu formuláře a udělám si kontejnery pro jednotlivé jazyky, nebo položky a jazyky v tom, to už je jedno. Nemusím řešit ádné klonování apod. ne?
- kuba1999
- Člen | 13
Jiří Nápravník napsal(a):
Nevím, jestli úplně chápu, ale šel bych na to tak, že si předám seznam všech těch jazyků, předám té továrně na tvorbu formuláře a udělám si kontejnery pro jednotlivé jazyky, nebo položky a jazyky v tom, to už je jedno. Nemusím řešit ádné klonování apod. ne?
Takto budu muset ale mít továrnu pro každý typ formuláře, ne? Chtěl bych, abych továrně předal jakýkoliv formulář a ta mi zduplikovala všechny jeho prvky pro ostatní mutace a dala mi je do kontejnerů.
Stále si hraji s Kdyby replikátorem, ale nedaří se mi zařídit, abych prošel cyklu prvky formuláře a vytvořil jejich kopie.
- Oli
- Člen | 1215
Zkus se podívat kdyžtak na example
Zkus se podívat na tvorbu komponent s využitím autowiringu. Takhle se to dělá standardně.
Pokud by jsi ale chtěl, tak si napiš vlastní továrničku, která by ti vytvořila instanci na základě jména třídy, kterej bys zadal jako parametr. Tohle řešení se mi ale asi moc nelíbí.
- akadlec
- Člen | 1326
No nevím asi sem trochu mimo, ale snad vždy si ten form musíš někde nadefinovat ne? Nebo jej nějak magicky generuješ?
Já bych to řešil klasicky, tam kde definuju položky formuláře budu mít k dispozici seznam locale pro které to chci generovat a pro to vytvořil patřičné kontejnery. Řešit nějaké duplikování, klonování atd je imho špatně.
- kuba1999
- Člen | 13
akadlec napsal(a):
No nevím asi sem trochu mimo, ale snad vždy si ten form musíš někde nadefinovat ne? Nebo jej nějak magicky generuješ?
Já bych to řešil klasicky, tam kde definuju položky formuláře budu mít k dispozici seznam locale pro které to chci generovat a pro to vytvořil patřičné kontejnery. Řešit nějaké duplikování, klonování atd je imho špatně.
OK. Nic jiného mi nezbyde.
Chtěl jsem to spíše jen nějak zautomatizovat – než tohle psát u každé definice formuláře.
- akadlec
- Člen | 1326
Jak z automatizovat? Jak generuješ form, resp vytváříš jeho definici? Pokud je to nějaká magie tak si to tam budeš muset nějak implementovat, pokud je to klasicky:
$form->addText('name', 'Jméno:');
$form->addPassword('password', 'Heslo:');
$form->addSubmit('send', 'Registrovat');
Tak je už snad nejmenší tam dá cyklus co projde dostupné jazyky, případně si udělat nějakou metodu do BaseForm co by to aplikovala sama.
- kuba1999
- Člen | 13
akadlec napsal(a):
Jak z automatizovat? Jak generuješ form, resp vytváříš jeho definici? Pokud je to nějaká magie tak si to tam budeš muset nějak implementovat, pokud je to klasicky:
$form->addText('name', 'Jméno:'); $form->addPassword('password', 'Heslo:'); $form->addSubmit('send', 'Registrovat');
Tak je už snad nejmenší tam dá cyklus co projde dostupné jazyky, případně si udělat nějakou metodu do BaseForm co by to aplikovala sama.
Ano, formulář vytvářím klasicky (stejně). Pomocí cyklu jsem si to implementoval – ale psát u každého formuláře cyklus mi přišlo moc dobré…
public function createComponentAddEditForm()
{
$locales = array("cs", "en", "de");
$form = new AdminForm();
$c = $form->addContainer("title");
foreach($locales AS $locale)
{
$c->AddText($locale, "Titulek".($locale != "cs" ? "[".$locale."]":""), 50)
->setRequired();
}
$c = $form->addContainer("content");
foreach($locales AS $locale)
{
$c->addTextArea($locale, "Obsah".($locale != "cs" ? "[".$locale."]":""), 50)
->setRequired();
}
$form->addSubmit("save", "Uložit");
$form->onSuccess[] = $this->onSubmit_AddEditForm;
return $form;
}
Jak píšeš ohledně metody v BaseFormu, který by tohle udělala sama – mohl by si prosím naznačit, jak toho docílit bez použití klonování?
Snažil jsem se o něco takového, kde metoda makeMultilanguage
by zařídila vytvoření kontejneru a komponent pro ostatní jazykové
mutace.
$form = new MultilanguageForm();
$form->AddText("title", "Titulek", 50)
->setRequired()
->makeMultilanguage();
$form->addEditor("content", "Obsah")
->setRequired()
->makeMultilanguage();
$form->addSubmit("save", "Uložit");
Děkuji.
Editoval kuba1999 (9. 9. 2014 14:48)
- akadlec
- Člen | 1326
Tak ono udělat tam X foreach cyklu je špatně když stačí jen jeden ;)
public function createComponentAddEditForm()
{
$locales = array("cs", "en", "de");
$form = new AdminForm();
$form->addContainer("title");
$form->addContainer("content");
foreach($locales AS $locale) {
$form['title']->AddText($locale, "Titulek".($locale != "cs" ? "[".$locale."]":""), 50)
->setRequired();
$form['content']->addTextArea($locale, "Obsah".($locale != "cs" ? "[".$locale."]":""), 50)
->setRequired();
}
$form->addSubmit("save", "Uložit");
$form->onSuccess[] = $this->onSubmit_AddEditForm;
return $form;
}
A to co navrhuješ ty s tou metodou makeMultilanguage tak to můžeš udělat tak že si extenduješ formulářové elementy a tohle jim implementuješ. To by taky neměl být problém ;)
A to co jsem myslel já je to že si v base formu uděláš nějakou metodu makeMultilanguage co ti to vyřeší
class BaseForm extends Form
{
protected function makeMultilanguage($name, $title)
{
//...
return $element;
}
}
ale asi bych šel cestou extendování jednotlivých elementů
- kuba1999
- Člen | 13
No, vydám se spíše iterováním nad položkami formuláře.
Pokoušel jsem se to udělat pomocí extension metody, ale zde musím
použít klonování = formulář se vyrenderuje správně, jak chci, ale už
tam dělají neplechu rules
atd. (je to nepoužitelné)
Nette\Forms\Controls\BaseControl::extensionMethod("makeMultilanguage", function($component){
$form = $component->getForm();
$odlComp = $component;
unset($form[$component->name]);
$c = $form->addContainer($component->name);
$c->addComponent($odlComp, "cs");
$c->addComponent(clone $odlComp, "en");
$c->addComponent(clone $odlComp, "de");
$form['title']['en']->caption .= " [en]";
$form['title']['de']->caption .= " [de]";
return NULL; //s prvkem jiz dale nesmim pracovat
});