[Best Practise] Lokalizace formularu a komponent

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

Mam funkcni vlastni DbTranslator a hledam akorat snazsi cestu (mene psani – automaticky?) prekladani formulari a komponent.

Momentalne pouzivam toto:

Je predpoklad ze $this->translator je objekt implementujici rozhrani Nette\Localization\ITranslator
Form:

	protected function createComponentRandomForm()
	{
		$form = new Forms\RandomForm($dependencies);
		$form->setTranslator($this->translator);
		return $form;
	}

U formu to resim takto, da se resit i predavanim translatoru pres konstruktor a resit az v one tride (viz nize, to pouzivam u ostatnich neformularovych komponent).
Neda se to resit nejak pres spolecneho predka bez predavani vsech zavislosti, nebo je to opravdu best-way?

Komponenty:

	protected function createComponentRandomControl()
	{
		$component = new Components\RandomControl($this->translator, $otherDependencies);
		return $component;
	}

	// RandomControl.php:
	public function render()
	{
		//...
		$this->template->setTranslator($this->translator);
		//...
	}

Premyslel jsem nad vytvoreni factory, ktera by tyto komponenty obalila do dalsi komponenty, ktera by dostala translator a pripadne dalsi zavislosti primo z configu skrze factory.

Hledam pouze lepsi reseni a zpusob jak transparentne a automaticky prekladat vsechny komponenty + formulare, abych nemusel u kazdeho z desitek nove pridavanych formularu a komponent pamatovat na to, ze musim predat translator.

Jeste jsem se setkal s timto (BaseForm.php a BaseControl.php, ktere se extenduji ve formu namisto prislusnych UI class):

	public function __construct(Nette\ComponentModel\IContainer $parent = NULL, $name = NULL) {
		parent::__construct($parent, $name);
		$this->setTranslator(Nette\Environment::getContext()->translator);
	}

Toto mi prijde ale jako hodne hodne hooodne nepekne reseni.

Take me napadlo, co v attached metode volat neco ve smyslu

	$this->setTranslator($presenter->translator);

Jedna se ale o skrytou zavislost a nevim zda neni v attached na preklady jiz pozde (nezkousel jsem)

Predem diky za odpovedi.

Editoval Lexi (27. 8. 2013 9:49)

Filip Procházka
Moderator | 4668
+
0
-

Děláš to zbytečně složitě.

class BaseForm extends \Nette\Application\UI\Form
{
	protected function attached($parent)
	{
		parent::attached($parent);

		if (!$parent instanceof Nette\Application\UI\Presenter) {
			return;
		}

		$translator = $this->presenter->context
			->getByType('Nette\Localization\ITranslator');

		$this->setTranslator($translator);
	}
}

Když tvoje formuláře budou od tohoto dědit, nebo je budeš na tomto alespoň sestavovat, tak se ti vždy po připojení do presenteru translator nastaví.

Ale lepší je použít továničky.

jasir
Člen | 746
+
0
-

A nebo použij (taky hosiplanovo, uff :o) autowired component factories
kdyby/autowired, což je ten tvůj přístup přes factories.

Jan Mikeš
Člen | 771
+
0
-

Filip Procházka napsal(a):

Děláš to zbytečně složitě.

		$translator = $this->presenter->context

Ok, takze v attached neni pozde, neni ale context taky fujky? Kazdopadne lazy reseni to je, ale nevim jestli by pro me oko uz nebylo hezci $this->presenter->translator (translator mivam vzdy zaregistrovat v hlavnim BasePresenteru, takze se nemusim obavat ze by nekde chybel)

jasir napsal(a):
A nebo použij (taky hosiplanovo, uff :o) autowired component factories kdyby/autowired, což je ten tvůj přístup přes factories.

No jo, ale pokud se nemyslim tak to neudela nic jineho, nez ze mi prida service ITranslator do tovarnicky, odkud si stejne budu muset translator predat bud pomoci konstruktoru nebo nastavit ->setTranslator(), nebo jsi to myslel jinak?

Editoval Lexi (27. 8. 2013 18:17)

enumag
Člen | 2118
+
0
-

@Filip Procházka: Odkdy zrovna ty v Best Practice vlákně uvádíš context? :-O

Osobně nemám rád dědění třídy Nette\Application\UI\Form takže si Best Practice představuji přibližně takto:

class WhateverFormFactory extends \Nette\Object
{

	/**
	 * @var \Nette\Localization\ITranslator
	 */
	private $translator;

	public function __construct(\Nette\Localization\ITranslator $translator)
	{
		$this->translator = $translator;
	}

	public function create()
	{
		$form = new \Nette\Application\UI\Form;
		$form->setTranslator($this->translator);

		// define fields

		return $form;
	}

}
services:
	- WhateverFormFactory

Inject továrny v presenteru si díky Kdyby/Autowired ušetřím:

class WhateverPresenter extends BasePresenter
{

	/**
	 * @return My\Awesome\Datagrid
	 */
	protected function createComponentWhateverForm($name, WhateverFormFactory $factory)
	{
		return $factory->create();
	}

}

Editoval enumag (27. 8. 2013 18:39)

Filip Procházka
Moderator | 4668
+
0
-

Máte pravdu v tom, že context není best practise, v tomhle případě to ale ušetří opravdu hodně psaní.

Nejčistější řešení je mít na to buď konkrétní továrnu, nebo generovanou a v setupu mít volání setTranslator.

Jan Mikeš
Člen | 771
+
0
-

Diky, pomohli jste mi oba, v tomto pripade pouziji asi $this->presenter->translator v attached metode, sice to neni uplne transparentni ale zde mi to usetri hodne psani a nemusim prekopavat cely projekt.

Enumagovo reseni se mi take libi, je nejaky zasadni duvod proc nepouzivat extendovani UI\Form?
Nebo tam je pouze rozdil v pouzivani?

Rikam si, ze pokud budu vyuzivat ciste tovarny, tak prijdu o moznost dedicnosti jednotlivych formularu navzajem (subformulare..), sice stale mam kompozici a moznost pridavat containery, to ale nemusi uplne vzdy vyhovovat.

Ma to jine (ne)vyhody?

enumag
Člen | 2118
+
0
-

@Lexi:

Důvod jsem uváděl zde pro Permission. Pro formuláře platí přesně totéž. Není to až tak zásadní, je to prostě můj pohled na věc.

Pokud jde o znovuvyužití formulářů, doporučuji přečíst https://forum.nette.org/…nebo-tovarna.

Jan Mikeš
Člen | 771
+
0
-

Diky, tema od davida jsem cetl nejakou dobu zpatky, za tu chvili jsem se zase o kousek (spis kus) posunul, takze zkusim znova :) ostatni temata vypadaji take prinosne.

Filip Procházka
Moderator | 4668
+
0
-

Myslím že by bylo vhodné odkázat ještě i tuto stránku

Jan Mikeš
Člen | 771
+
0
-

Dopracoval jsem se k necemu takovemu, jenom si nejsem jisty jestli je to uplne ok, nebo by se to dalo jeste o neco vylepsit:

BaseFormFactory.php:

class BaseFormFactory extends Nette\Object {

	/** @var Nette\Localization\ITranslator */
	private $translator;

	public function __construct(Nette\Localization\ITranslator $translator)
	{
		$this->translator = $translator;
	}

	public function create()
	{
		$form = new Nette\Application\UI\Form;
		$form->setTranslator($this->translator);

		return $form;
	}
}

SomeFormFactory.php

class SomeFormFactory extends Nette\Object {

	/** @var BaseFormFactory */
	private $baseFormFactory;

	public function __construct(BaseFormFactory $baseFormFactory)
	{
		$this->baseFormFactory = $baseFormFactory;
	}

	public function create()
	{
		$form = $this->baseFormFactory->create();
		// ...
		return $form;
	}

	// ...
}

Neni to uz moc prekombinovane s temi tovarnami? Me to pripada v poradku, ale 100% jisty si tim nejsem.
Jde o to, ze baseform krom translatoru obsahuje i jine veci, antispam, muze prijimat i jine sluzby a chci se vyhnout tomu, abych pri nahodnem pridani sluzby, kterou bych chtle vyuzivat ve vsech formech musel editovat vsechny konstruktory vsech tovarnicek.

enumag
Člen | 2118
+
0
-

Hmm, používám totéž ale s dědičností místo skládání, tahle možnost mne přiznám se nenapadla a teď jsi mne znejistil.

@Filip Procházka: Co si myslíš o dědičnosti vs. skládání v tomto případě?

Milo
Nette Core | 1283
+
0
-

Trochu OT… Nepotýkáte se pak s problémem, že u továren je vlastně každý formulář UI\Form? Hůř se hledá, kde všude v aplikaci je formulář použit a nelze používat přesný typehint. Je to spíš akademický problém, ale nebylo by lepší podědit UI\Form a na něj pak továrnu?

class AnyFrom extends UI\Form {}

class AnyFormFactory extens Nette\Object {
	function create() {
		$form = new AnyForm;
		return $form;
	}
}
Filip Procházka
Moderator | 4668
+
0
-

@enumag Víc se mi líbí @Lexi-ho řešení :) Je lépe rozšiřitelné a o ždibíček čistější.