Umístění modulů v adresářové struktuře
- danik
- Člen | 56
Ahoj Netti! :o)
Tak si trochu začínám hrát a po delší době se vracím k Nette (nebo lépe řečeno pěkně rovnou po hlavě skáču do 1.0dev na PHP 5.3). Zkouším si jenom takovou jednoduchou hloupost, abych přišel na to, co se za ten půlrok, kdy jsem neNettil, změnilo. Narazil jsem na věc, která mě zarazila: doporučená adresářová struktura teď vypadá tak, že jednotlivé moduly jsou umístěné přímo do APP_DIR:
- APP_DIR
- /WebModule
- /AdminModule
- /temp
- /config.ini
- /bootstrap.php
No a mně to připadá nepřehledné, mít moduly v jedné hromadě
s configem a bootstrapem etc. Jsem zvyklý mít samotné moduly
v podadresáři /modules
. Tak jsem si říkal: dřív to šlo
nějak ohnout, jak vono to… a vzpoměl jsem si, že se v configu nastavovalo
něco jako variable.presentersDir = "%appDir%/modules"
. Zkouším
to – a ono nic! Říkám si, co by za tím mohlo být, provrtávám se Nette
postupně přes PresenterLoader, který mi na začátku vyhodil výjimku
o nenalezeném prezenteru, do Application, kde se PresenterLoader volá, odtud
do Environment, do ServiceLocatoru, do Configuratoru, zpět do ServiceLocatoru a
odtud zpět do Application, kde konečně nalézám to, po čem jsem prahnul:
továrničku na PresenterLoader, která jej při vytváření obdaří
parametrem basePath. A tady nastává můj převeliký údiv, protože
Application předává PresenterLoaderu jako basePath natvrdo appDir.
Čímž, mimojiné, efektivně dělá z doporučené adresářové struktury adresářovou strukturu povinnou: přece nemůžu přepisovat app dir! Protože je továrnička statická, vytvořit potomka Application a překrýt továrničku se neukázalo jako funkční řešení. Můžu si to samozřejmě přepsat přímo ve frameworku, ale radši bych si uřízl dva prsty než bych jakkoliv sahal do Nette :o)
Tak jsem se chtěl jen tak zeptat, jestli tohle je „správné, definitivní a vědomé“ chování frameworku nebo jestli něco přehlížím nebo jestli se to třeba bude nějak měnit etc.
Jinak po dlouhé době opět musím napsat dvě slova: Nette vládne!
Díky moc za Framework s velkým F.
- danik
- Člen | 56
Oumajgát! Super, díky moc! No ale každopádně je to možná námět k diskuzi – nebylo by dobré třeba na to vytvořit obecně proměnnou prostředí „modulesDir“, jejíž výchozí hodnota by byla „%appDir%“? Pak by šlo v configu jednoduše změnit tuhle proměnnou a nemusely by se vytvářet továrničky.. nebo já teda nevim, je ještě někdo, kdo nechce (stejně jako já) používat APP_DIR/JakysiModule?
- Vyki
- Člen | 388
Já osobně používám adresářovou strukturu, kde mi přijde logické mít moduly v APP, ale fungovat by ti to mělo všude kde ti to může prohledat robot loader. Stačí mu v config.ini říct ať nehledá jenom a app a libs. Když budeš mít třeba strukturu
/app
/libs
/modules
a robot loader ti to načte i z toho modules tak by to mělo běhat. Ty
presentrery presenterLoader hledá v adr. struktuře
v případě, že tu třídu nemá v cache a tam jí mít bude díky robot
loaderu. Jediné co bude zřejmě třeba upravit jsou metody
formatLayoutTemplateFiles
a formatTemplateFiles
. Ty si
přepíšeš do svého basePresenteru
. Používám adr.
strukturu:
/images
/css
/application
/app
/AModule
/Backend
/Frontend
/BModule
/Backend
/Frontend
/bootstrap.php
/config.ini
.
.
.
/libs
Editoval Vyki (9. 7. 2010 19:08)
- Ani
- Člen | 226
PresenterLoader se musí přepsat, protože generuje třídu/cestu pro
odkazy. Tj. robotloader to načte, ale jakému linku odpovídá jaká
třída/soubor, určuje PresenterLoader.
Minimálně tak nějak mi to fungovalo, když jsem to přepisoval, třeba je to
jinak. :)
Editoval Ani (16. 7. 2010 19:47)
- Vyki
- Člen | 388
Taky jsem si kdysi napsal vlastní presenterLoader, ale jak mi správně napověděl Honza Marek, presenterLoader slouží principielně pouze ke zjištění názvu třídy. Sem jsem dal ke stažení příklad, kde je demostrována následující adr. struktura:
/index.php
/css
/application
/app
/libs
/modules
/FrontModule
/presenters
/templates
/ExportModule
/presenters
/templates
/AdminModule
/presenters
/templates
Je to prostě upravený příklad modules-usage z distribuce. Co je jinak?
V index.php je přidána konstanta MODULES_DIR
. V bootstrapu je
registrována env. proměnná modulesDir
. Inicializaci Robot
loaderu a registraci adresářů app, libs, modules provádím
v bootstrapu. V basePresenteru jsou přepsány metody
formatLayoutTemplateFiles
a formatTemplateFiles
.
Upravené v nich je to, že jsem tam nechal pouze blok kódu pro novou
strukturu modulů a $appDir = Environment::getVariable('appDir');
přepsal $appDir = Environment::getVariable('modulesDir');
. Běhá
to v pohodě.
Jelikož presentery nejsou na místech, kde by je presnterLoader čekal v případě, že nejsou v cache robotLoaderu, klade to větší důraz na smazání cache robotLoaderu, než při klasické adr. struktuře. Při každém přidání presenteru musí být adresářová struktura znovu zaindexována do cache robotLoaderu!
Editoval Vyki (13. 11. 2010 11:53)
- cmelis
- Člen | 26
Díky moc za příklad ke stažení, podařilo se mi to z něj pochopit jak to funguje :). Jinak ještě jsem se chtěl zeptat jak by se dali lépe nastavit routy? Teď když mám:
<?php
$router[] = new Route('<presenter>/<action>/<id>', array(
'module' => 'Front',
'presenter' => 'Homepage',
'action' => 'default',
'id' => NULL,
));
?>
tak se mi při dotaz na Module ve složce FrontModule/StatsModule/presenters… zobrazí URL jako doména/stats.overview/
Jde do routy nějak nastavit jeden a druhý modul abych si místo tečky mohl dát / nebo případně pomlčku atd?
Díky za odpověď :)
- Vyki
- Člen | 388
<?php
class routeDicrionary
{
public function __construct() {
throw new InvalidStateException('Cannot load a static class:'. __CLASS__);
}
public static function register()
{
Route::addStyle('#pres');
Route::setStyleProperty("#pres", Route::FILTER_IN, callback(__CLASS__, 'aliasToPresenter'));
Route::setStyleProperty("#pres", Route::FILTER_OUT,callback(__CLASS__, 'presenterToAlias'));
}
public static function aliasToPresenter($alias)
{
$aliases = array(
'statistiky' => 'Stats:Overview',
);
if(isset($aliases[$alias]))
return $aliases[$alias];
else
return NULL;
}
public static function presenterToAlias($presenter)
{
$aliases = array(
'Stats:Overview' => 'statistiky',
);
if(isset($aliases[$presenter]))
return $aliases[$presenter];
else
return NULL;
}
}
routeDicrionary::register();
$router[] = new Route('<presenter #pres>/<action>/<id>', array(
'presenter' => 'Front:Homepage',
'action' => 'default',
'id' => NULL,
));
?>
Překladový slovník je mocný nástroj. Dájí se s tím vytvořit i složité routy aniž by se navzájem tloukly. Pokud těch rout máš, ale málo, možná je to až moc silný kalibr, na řešení takového problému.
Editoval Vyki (24. 10. 2010 19:21)
- cmelis
- Člen | 26
Díky mrknu na to.
Jinak jsem si všim, že v tom tvým examplu se vůbec nenačítá config.ini (teda aspoň mě). Stačí přidat do bootstrap.php
<?php
Nette\Environment::loadConfig(APP_DIR."/config.ini");
?>
Sice se mi to stejně zatím nepodařilo rozchodit ten robotloader bez inicializace v bootstrapu ale třeba přehlížím ještě něco jinýho :)
- Vyki
- Člen | 388
Ten příklad jsem předělal pro verzi Nette 2.0 alfa, můžeš to zkusit stáhnot znova. Starší verze, (ta která tam byl předtím) měli problém s načtením parametrů robot loaderu z config.ini (libs a app se načítaly, ale pokud byl přidán další řádek, tak s tím si to neporadilo). Bral bych to pouze jako příklad, že adr. struktura jde dost přizpůsobit, nevím jestli je úplně ono dávat moduly mimo adresář APP.