Formulář pro administraci vícejazyčného obsahu

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
kuba1999
Člen | 13
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

@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
+
0
-

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
+
+1
-

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?

Oli
Člen | 1215
+
0
-

@JiříNápravník No není to zhruba to co jsem myslel já? Ono je v podstatě jedno jestli použiješ multiplier a interface, kterej ti tu továrnu udělá nebo napíšeš přímo továrnu a v té to explicitně zavoláš víckrát nebo ne? Nebo jsem něco nepochopil? :-)

kuba1999
Člen | 13
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

Dobře, děkuji ti za odpověď.

kuba1999
Člen | 13
+
0
-

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