Jak vytvořit objekt pomocí továrničky definované v configu?

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

Ahoj,
nikdy jsem nepoužíval továrničky pomocí configu. Mám s tím ale tak trochu problém.

  1. Když jsem jel podle dokumentace (en), tak první co, že nemám používat factories, že jsou deprecated. Jasně chápu, přesouvám do služby.
  2. Továrničku jsem si udělal podle dokumentace ve službě a zkusil zavolat
service:
	poll:
		class: Component\Poll\Polls(@pollRepository)
		autowired: no
public function createComponentPoll() {
	return $this->context->createPoll;
}

Tohle mě nadalo, že createPoll neexistuje. Pokud název service přepíšu na createPoll, tak to funguje, ale řekl bych, že to už nevyrábí továrnička, ale volám přímo službu.

  1. zkouším teda radu, na kterou jsem náhodou narazil na foru. To mě zase nadalo, že neexistuje klíčové slovo implements

Mohl by mě prosím někdo ukázat nějaký jednoduchý ucelený příklad, jak použít továrničku definovanou v configu?

Ještě dodám, že používám Nette 2.1

nanuqcz
Člen | 822
+
0
-

Ahoj,
továrničky v novém Nette jsem ještě nepoužil. Ale tuším, že jsem na fóru zahlídl něco takového:

// v presenteru
$this->context->createService('poll');  // vytvoří vždy novou instanci
David Matějka
Moderator | 6445
+
0
-

radeji pouzij generovane tovarnicky, https://doc.nette.org/…tion/factory

Oli
Člen | 1215
+
0
-

matej21: Díky. Použil jsem ten návod „Jak si ušetřit psaní“. Ještě by mě zajímalo, jak dostat do konstruktoru (respektive do té třídy) parametry z configu?

nanuqcz: Díky. Přes ten context se mě to ale tak nějak líbí míň, než když to můžu normálně injectnout do třídy.

Ještě takovej akademickej dotaz, jakej je rozdíl mezi $this->context->createService('poll'); a interface, když oba způsoby v podstatě dělají totéž (novou instanci třídy)?

David Matějka
Moderator | 6445
+
0
-

@Oli: v neonu

services:
	-
		class: Component\Poll\Polls(@pollRepository)
		implement: Component\Poll\PollsFactory

Ještě takovej akademickej dotaz, jakej je rozdíl mezi $this->context->createService('poll'); a interface, když oba způsoby v podstatě dělají totéž (novou instanci třídy)?

je to o tom, ze diky factory mas jasne definovanou zavislost, nejsi zavisly na contextu, kterym skryvas realne zavislosti

Editoval matej21 (6. 2. 2014 21:08)

Vojtěch Dobeš
Gold Partner | 1316
+
+1
-

Předávání parametrů zatím ve článku chybí, ale udělá se to takto:

services:
	-
		create: Component\Poll\Polls(%foo%)
		implement: IFactory
class Polls
{
	public function __construct($foo, PollsRepository $pollsRepository)
	{
		...
Oli
Člen | 1215
+
0
-

matej21, vojtech.dobes: Díky kluci.

Nebylo by špatný napsat to buď do dokumentace nebo na planette. V dokumentaci se pořád popisuje použití s factories, které už v Nette 2.1 nejsou. Poslal bych pull request, ale obávám se, že kromě toho co jste mě tu teď poradili neznám další možnosti :-)

Oli
Člen | 1215
+
0
-

Tohle už úplně nesouvisí s továrničkou, ale jak deklaruju v configu třídu, které předám nějaký parametry z presenteru, nějaký z neonu a kterej bude obsahovat nějaký setmetody? Ty set metody bych ani tak nepotřeboval, to jen tak pro úplnost, někde jsem to totiž viděl, že to jde.

Chtěl bych config napsat tak, abych mohl použít constructor takhle:

public function __construct($lang, $defaultLang, $translator) {
	$this->lang = $lang; // předávám z presenteru
	$this->defaultLang = $defaultLang; // z neonu
	$this->translator = $translator; // z neonu
}

Díky

Vojtěch Dobeš
Gold Partner | 1316
+
0
-
services:
	-
		create: Component\Poll\Polls(%lang%, %defaultLang%) # (%lang%, %defaultLang%, @translator) při nevyužití autowiringu
		implement: IFactory
		parameters: [lang]
		setup:
			- setDefaultLang(%defaultLang%)
			- setTranslator() # setTranslator(@translator) při nevyužití autowiringu
interface IFactory
{
	/** @return \Component\Poll\Polls */
	function create($lang);
}
Oli
Člen | 1215
+
0
-

Super, díky.

Mesiah
Člen | 240
+
0
-

vojtech.dobes napsal(a):

Taky nemám zkušenost s dynamickými továrnami, tak mě prosím neukamenujte, když to špatně poberu, ale chápu správně, že pak jen v továrničce komponenty, Poll jak už je tady zmíněno, zavolám $this->myInjectedInterfaceControl->create('cs');?
V případě, kdy parametr lang nevyplním, vyskočí mi exception/notice?
Je možné dát jako parametr persistentní parametr, v neon configu?

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

Přesně tak, v továrničce si člověk zavolá metodu create na továrně.

Když se parametr lang nepředá, tak to zařve na chybějícím argumentu.

Konfigurace o persistentních parametrech nic neví, takže ne.

Oli
Člen | 1215
+
0
-

@vojtech.dobes: Tak jsem se dostal k tomu to vyzkoušet, ale nefunguje mě to a nejsem schopnej přijít na to, kde dělám chybu. Mám dva parametry, které přijímá constructor. Jeden bych potřeboval jako id a druhý závislost na repository. Oba ale dostanou to repository. Na tohle bych v podstatě ani factory nepotřeboval, jen bych chtěl předat oba ty parametry (id a optionRepository) do konstruktoru. Mám to takhle:

poll:
	class: Component\Poll\Polls(@poolOptions, dalsi zavislosti)
	implement: IPollsFactory

poolOptions:
	class: Component\Poll\Options(@optionRepository)
	implement: Component\Poll\IOptions
	parameters: [id]
	setup:
		- setOptionRepository()
// IOptions
interface IOptions
{
	/** @return \Component\Poll\Polls */
	function create($id);
}
// Options
public function __construct($id, \Repository\OptionRepository $answersRep)
{
	$this->id = $id; // dostane taky instanci \Repository\OptionRepository
	$this->answersRep = $answersRep;

}
// Polls
public function __construct(IOptions $options)
{
	$this->options = $options;
}

public function render()
{
	$this->template->options = $this->options->create($this->id);
}
David Matějka
Moderator | 6445
+
0
-

musis rict, kam to id predat:

poolOptions:
    class: Component\Poll\Options(%id%, @optionRepository)
    implement: Component\Poll\IOptions
    parameters: [id]
    setup:
        - setOptionRepository() #wtf?
Oli
Člen | 1215
+
0
-

matej21: Jasně už to vidím, díky ;-)