Automatické načítání Modelů v Nette2

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

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)

futuretux
Člen | 24
+
0
-

Na tohle jsem už koukal, ale přislo mi to trochu jako overkill. Ve staré verzi to fungovalo automactiky, tak si říkám jestli to není jenom v nějaké berličce v configu.

nanuqcz
Člen | 822
+
0
-

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

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.

futuretux
Člen | 24
+
0
-

Aha, tak díky za vysvětlení. Teď chápu co se změnilo v tom přístupu. Takže zkusím vsadit na ten model loader.

joe
Člen | 313
+
0
-

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

@**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)

Aurielle
Člen | 1281
+
0
-

Při testování svého kódu nemůžeš statické volání vyměnit za nějakou jinou instanci jiného objektu, to je tuším hlavní nevýhoda. Ale sám jsem se k testům taky ještě nedostal…

joe
Člen | 313
+
0
-

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

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;
?>
joe
Člen | 313
+
0
-

Ale musíš pro to použít speciální proměnnou a to je zbytečný. A navíc se mi to zdá jako práce navíc a líbí se mi víc to property-ready, stačí to napsat jen jednou. Ale třeba se to někomu bude hodit :-)