Umístění modulů v adresářové struktuře

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

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.

na1k
Člen | 288
+
0
-

Vlastní továrničku zaregistruj v configu ;-)

service.Nette-Application-IPresenterLoader.factory = "System\PresenterLoader::createPresenterLoader"
danik
Člen | 56
+
0
-

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?

Ani
Člen | 226
+
0
-

Já to mám taky předělané, takže by proměná asi našla uplatnění.

Vyki
Člen | 388
+
0
-

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

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

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

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

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

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.