Generované továrničky v Nette 2.1
- Šaman
- Člen | 2659
Nejdřív malé shrnutí toho jak napsat generovanou továrničku, protože v dokumentaci je stále již nedoporučovaný způsob.
Máme nějakou komponentu:
<?php
/**
* Komponenta přihlašovacího formuláře.
*/
class LoginForm extends Control
{
…
}
?>
Tuto komponentu nechceme vytvářet v presenteru pomocí operátoru
new
(z mnoha dobrých důvodů, které ale nejsou tématem tohoto
dotazu). Takže si na ni vytvoříme tovární třídu a tu si zaregistrujeme
jako službu v configu. Počkat, to je moc psaní. Nette za nás tuto tovární
třídu umí vygenerovat samo, když mu řekneme jakou komponentu chceme
vytvářet. Potřebujeme jen rozhraní:
<?php
/**
* Rozhranní pro generovanou továrničku.
*/
interface ILoginFormFactory
{
/** @return LoginForm */
function create();
}
?>
V konfigu si necháme vytvořit službu podle tohoto rozhraní
services:
- ILoginFormFactory
… a pak v presenteru můžeme využívat vygenerovanou službu LoginFormFactory:
<?php
/**
* Aplikační presenter.
*/
class ApplicationPresenter extends BasePresenter
{
/**
* @var ILoginFormFactory
*/
protected $loginFormFactory;
/**
* Injector.
*/
public function injectLoginFormFactory(ILoginFormFactory $loginFormFactory)
{
$this->loginFormFactory = $loginFormFactory;
}
/**
* Vytvoří komponentu loginForm.
* @return LoginForm
*/
protected function createComponentLoginForm()
{
return $this->loginFormFactory->create();
}
}
?>
A teď pár dotazů:
Výše uvedený způsob funguje nad aktuální stabilní verzí (2.1.1).
V dokumentaci jsou bohužel stále generované továrničky řešené pomocí
sekce factories
, která je v 2.1 deprecated. A na fóru jsem
našel několik doporučení, jak tyto továrničky psát, ale zápis je delší
a nevím, v čem je jeho výhoda.
- V definici služby se doporučuje vypnout autowiring. Proč? Továrna je přece úplně obyčejná služba, která má konkrétní rozhranní pomocí kterého ji mohu injectovat všude, kde potřebuji LoginForm.
# proč se doporučuje tento zápis?
services:
-
class: ILoginFormFactory
autowired: no
- Pak jsem viděl i tento zápis, ale nějak nevím, v čem je jeho výhoda. V presenteru s tím pracuji stejně, jako v ukázce nad čarou, nebo ne?
services:
-
class: LoginForm
implement: ILoginFormFactory
Děkuji za připomínky.
Teď se peru s předáváním parametru pomocí metody create
, až
mi to bude v základu fungovat, hodím to sem taky, ať to máme pohromadě
v jenom dobře dohledatelném vlákně.
Editoval Šaman (13. 2. 2014 17:44)
- David Matějka
- Moderator | 6445
- to doporuceni
autowired: no
je pro stare tovarnicky (takove to$context->createSomething()
, nyni myslim$context->createService('something')
), nevztahuje se na generovane tovarnicky - class je nutno specifikovat pokud nemas uvedenou @return anotaci. bylo to take nutne, pokud jsi uvadel argumenty – v dev uz to nemusis uvadet
Editoval matej21 (13. 2. 2014 18:01)
- Šaman
- Člen | 2659
Díky. Chápu to tak, že to nad čarou je nejkratší možný best practise
na generované továrničky. (Zkrátit by to šlo ještě pomocí property
injection do presenteru – anotace @inject).
Vypnout autowired je zbytečné a ten druhý způsob pod čarou se použije
pokud potřebuji třídě předat parametry, nebo provést nějaké další
nastavení.
- Vojtěch Dobeš
- Gold Partner | 1316
@zimmi Stačí komponentu z továrničky vrátit – bude k rodiči připojena automaticky. Je třeba se ujistit, že se to tak provádí v celé hierarchii.
- vojty
- Člen | 19
vojtech.dobes napsal(a):
@zimmi Stačí komponentu z továrničky vrátit – bude k rodiči připojena automaticky. Je třeba se ujistit, že se to tak provádí v celé hierarchii.
Tak nevím co dělám špatně, mám komponentu App\Neco, App\NecoFactory která implementuje App\INeco s metodou create která vrací App\Neco
neon takto:
<?php
neco: App\NecoFactory
?>
presenter:
<?php
/**
* @return \App\Neco
*/
protected function createComponentNeco()
{
return $this->context->neco->create();
}
?>
to bohuzel vrati err:
Component '' is not attached to ‚Nette\Application\UI\Presenter‘
pokud to trochu poupravim a připojim ho k prezenteru ručně tak to funguje
<?php
/**
* @return \App\Neco
*/
protected function createComponentNeco()
{
return $this->context->neco->create($this, 'neco');
}
?>
ale to se mi zdá fakt nějaký divný:)…zvojtil jsem „neco“? :) Jinak používám v2.2
Editoval vojty (25. 5. 2014 16:49)
- vojty
- Člen | 19
enumag napsal(a):
Evidentně používáš
$this->getPresenter()
v konstruktoru té třídy App\Neco. To je ale příliš brzy, komponenta v tu chvíli ještě nemá vazbu na presenter. Běžným řešením je metoda attached.
Hmm…díky. Metodu $this->getPresenter() v App\Neco používám, ale ne v konstruktoru…to je právě divný. Mohl bys mi prosím, ještě prosím trochu osvětlit ten postup s attached?
Bdw. dřív jsou to používal takto:
<?php
factories:
neco:
parameters: [parent, name]
arguments: [%parent%, %name%]
class: App\Neco
?>
třída vypadá zhruba takto:
<?php
class Neco extends Nette\Application\UI\Control
{
public function udelej($name, $vars)
{
...
$link = $this->getPresenter()->link($name, $arr)
}
...
...
}
?>
Edit:
Tak moje chyba, neuvědomil jsem si, že nemůžu udělat toto:
<?php
public function createComponentNeco()
{
$neco = $this->context->neco->create()
$neco->udelej(...)
return $neco;
}
?>
Jaký je tedy ted best practise pro připojení k prezenteru ihned? Díky.
Editoval vojty (25. 5. 2014 18:07)
- Tomáš Jablonický
- Člen | 115
Škoda, že se nedá nějakým způsobem ten interface vytvořit v neonu – tedy, že by si to Nette samo vytvořilo. Nebo to jde?
- David Matějka
- Moderator | 6445
@jablon: nastesti nejde :) nette se pouze stara o implementaci existujiciho interface