Automatické načítání Modelů v Nette2
- futuretux
- Člen | 24
Ahoj,
zatoužil jsem se naučit s Nette 2 – před časem jsem dělal pokusy se
starou verzí Nette, ale po čase to vzdal. Nette 2 se mi líbí o hodně
víc, ale mám trochu potíže s automatickým načítáním modelů.
Ve staré verzi stačilo udělat $this->model = new XXXModel a povedlo se vytvořit správnou instanci modelu.
V Nette 2 mám problém s tím, že model sice najde, ale není schopen mu správně předat instanci $database.
Po docela dlouhém experimentování jsem přišel, že funguje
v configu:
model:
class: Model
arguments: [@database]
class: XXXModel
arguments: [@database]
XXXModel přirozeně dědí od Model. Ono to v podstatě funguje stejně jako „za stara“, ale přijde mi nesmyslné všechny ty Modely vypisovat do configu. Před tím to šlo bez toho.
Jak se dá zařídit, abych nemusel všechny modely vypsat do configu? Examples mi moc nepomohli: když už je někde model, tak jen jeden a je to tam řešeno zápisem do configu.
Editoval futuretux (27. 7. 2011 18:54)
- nanuqcz
- Člen | 822
Pokud se ti líbil starý způsob, můžeš v presenteru použít
$this->model = new XxxModel($this->getService('database'));
.
V Nette 2.0 je ale „moderní“ strkat to všechno do configu, anebo
využít výše zmíněný odkaz.
A napadl mě ještě další způsob, jak to všechno zfouknout (a myslím že i čistě) v presenteru:
function startup()
{
parent::startup();
$this->container->addService('xxxModel', function($context){
return new XxxModel($context->database);
});
}
function renderDefault()
{
$this->template->xxx = $this->getService('xxxModel')->getXxx();
}
- Filip Procházka
- Moderator | 4668
Přidávat služby v presenteru je otřesné. Container
by jsi
po Application::run()
neměl vůbec upravovat, pouze požívat.
Je legrační jak si všichni myslí, že když si udělají
BaseModel
, který bude konstruktorem přijímat připojení
k databázi, tak se tam dostane „samo“ nebo „automaticky“. Tak to, ale
vůbec není, něco to tam musí dostat.
ModelLoader
není vůbec overkill, ale zdaleka nejjednodušší
řešení, které automatizuje to předávání připojení do jednotlivých
modelů.
Nic se automaticky v předchozích verzích Nette nedělo. Důvodem proč
jsi si pravděpodobně myslel, že se něco načítá automaticky je
RobotLoader
, který je v současné verzi Nette také. Takže
třídy se pořád načítají „automaticky“ (bez nutnosti psát
require
nebo include
), pokud jsou ve složkách,
které hlídá. A nebo také dibi
, které můžeš mít v Nette
pořád a můžeš ho používat pořád i staticky pomocí statické třídy
dibi
. Nic ti v tom nebrání. Snad jen svědomí a testovatelnost,
ale to tě s tvým současným přístupem určitě ještě dlouho zajímat
nebude.
Jediný rozdíl je v tom, že teď se dostaly do Nette nástroje, které mají více podporovat Dependecy Injection.
Pokud máš ještě nějaké dotazy (i po přečtení dokumentace), pak se klidně ptej.
- joe
- Člen | 313
@HosipLan:
staticky pomocí statické třídy dibi. Nic ti v tom nebrání. Snad jen svědomí a testovatelnost
Já bych se taky zeptal, jaká je nevýhoda v tom používat statické dibi?
Můžeš to prosím tě vysvětlit, jak jsi to myslel s tou testovatelností?
Nějak taky nemůžu přijít na to, proč bych neměl psát v modelech
statické metody, protože zápis Model::metoda
, mi přijde daleko
jednodušší, kratší a rychlejší, než zavádění nějakého ModelLoaderu
(pokud bych modely chtěl načítat automaticky) a pak v presenterech psaní
$this->models->foo->metoda()
. Jaké tam jsou tedy
nevýhody a proč bych je neměl psát staticky? Díky za upřesnění.
- Filip Procházka
- Moderator | 4668
@**joe**: Ty jsi nečetl článek Dependecy Injection ? Jde o to, že u statických tříd se nemůžeš spolehnout na to, co všechno ovlivňují a co potřebují ke své existenci. Nemůžeš proto testovat jejich chování za různých podmínek. Což odporuje Unit testům a znovupoužitelnosti.
Dibi je velice chytře udělané, takže jde používat i bez statické obálky. Stačí místo
$connection = dibi::connect(array(/* ůdaje k databázi, jako v configu */));
$connection->query('SELECt * FROM ...');
dibi::query('SELECt * FROM ...');
použít
$connection = new DibiConnection(array(/* ůdaje k databázi, jako v configu */));
$connection->query('SELECt * FROM ...');
dibi::query('SELECt * FROM ...'); // nebude fungovat
Vytvoření DibiConnection
jako služby jde zapsat i v configu
a pak předávat modelům, ať jednotlivě vypsaným, nebo vytvářeným přes
modelLoader.
Editoval HosipLan (28. 7. 2011 15:29)
- joe
- Člen | 313
Tak díky, už tomu rozumím. Došel jsem k jednoduchému testování PHPUnit (jsem ani nevěděl, že taková šikovná věc existuje :)). Ale trochu k tématu, využil jsem dynamické načítání modelů, funguje bezvadně, ale v takovém případě nefunguje napovídání IDE (code completition v NetBeans). Neznáte na to prosím nějaký trik, jak donutit aby mi i při dynamickém načítání napovídal metody z konkrétního modelu? Moc by to pomohlo, díky
Tak to jde celkem jednoduše pomocí anotace @property-read
Editoval joe (19. 8. 2011 5:26)
- natrim
- Člen | 73
v netbeans se da používat @var
<?php
class Test{
/**
* @var \Nette\Object
*/
public $promena;
}
// pak také
/* @var $test \Nette\Object */
$test = new \Nette\Object
//a lze napovidat i ze service
/* @var $sluzba \Models\Test */
$sluzba = $context->getService("Test");
//pripadne magicky: $sluzba = $context->test;
?>