Administrace jako extension
- Toanir
- Člen | 57
Ahoj,
Já modularitu řeším nějak následovně:
- mám v aplikaci malou
routovací extension
- tu konfiguruju tak, že jí nakrmím routovacími moduly, ze kterejch má poskládat finální aplikační router
- samotný routovací modul, třeba CmsRouterModule, funguje v podstatě jako běžná RouterFactory.
Nepovažuju to za nějakým způsobem kanonický řešení ale takhle se mi to vesměs líbí… Ještě to má značnej prostor pro zlepšování a ve výsledku bych se chtěl vyhnout explicitnímu routovacímu modulu a místo toho je zabalit do jakejchsi aplikačních modulů ale to je cesta, kterou jsem si ještě neprošlápl a ještě nevím, jestli se mi bude líbit…
Nicméně bych řekl že tenhle přístup může zhruba sloužit jako inspirace, jak to zadrátovat dohromady. :)
- David Matějka
- Moderator | 6445
ahoj,
v dokumentaci najdes vsechny zakladni veci https://doc.nette.org/…n/extensions –
vcetne konfigurace, nacitani sluzeb z neonu atd.
na pokrocilejsi veci se muzes kouknout do ruznych existujicich extensions, treba v kdyby/console muzes videt, jak se necha vyresit router
- dehtak
- Člen | 113
Jde mi o to mit administraci pro vice domen. Skousel jsem to prez module ale neni to ono. Snazim se o to, udelat administraci jako samostatnou aplikaci, ale aby zdedila databazovy pripojeni od urcity domeny. Skusim to namalovat k pochopeni. Dejme tomu ze to je hosting, mam tam 3 weby
Web 1 = domain1.cz
-app
-tmp
-log
-www
web 2 = domain2.cz
-app
-tmp
-log
-www
web 3 = domain3.cz
-app
-tmp
-log
-www
Administace
-app
-tmp
-log
Administrace bude vzdy volana domain1.cz/admin nebo domain2.cz/admin, nebo prez subdomenu admin.domain1.cz (administrace nepotrebuje slozku www jelikoz se index nacita z www prislusnyho webu, tudiz nemuze mit svuj boostrap) a tady je kamen urazu. Kdyz sem to mel ale jako modul tak %appDir% byl vzdy treba web1/app a takze pak bych musel spat veci co patri do administrace do web1/app slozky. Jelikoz nektery extension proste tu appdir vyzaduji.
Chci aby se Administrace chovala jako app prezentery routry config , fabricky
atd..
Nevim jak toho docilit uz si nad tim lamu hlavu nekolik tydnu. Administrace je
vlastne porad to same jen pracuje pak s jinym db pripojenim prislusnyho webu.
Popripade kdyby nakej web mel neco extra navic tak to nejak pridat pred
extension
Admin muze bejt klidne i ve vendoru to je jedno. Ale prijde mi zbytecny cpat
administraci (jedno a to same) do kazdy app slozky prislusnyho webu.
Proste chci udelat novej web udelam sablonu zkopiruju app od jinyho webu
udelam db pripojeni prdnu na hosting hotovo.
V administraci ponastavim.
Editoval dehtak (27. 4. 2020 22:08)
- Toanir
- Člen | 57
Nezkoušel sis hrát s rewrite pravidlama cílovejch aplikací? Mohl bys mít administraci jako úplně běžnou standalone appku, která bude rozpoznávat víc domén…
Standardně nette běží v nastavení že se ti vše, co není soubor, pŕepisuje na www/index.php. Před tohle přepsání bys mohl ještě přidat, že když máš na začátku url /admin, přepíšeš to na, třeba ../administrace/www.
Pak by to šlo vyřešit ještě že by jednotlivý aplikace integrovaly administraci jako balíček ale bylo by to docela dost konfigurace.
- Toanir
- Člen | 57
Hehe, řešení balíčkem jsem začal rozepisovat a pak jsem se v tom zamotal a kydž jsem si znovu přečetl tvojí zprávu s přepínačem v bootstrapu, napadl mě přepínač ještě před ním v podobě rewritu. :P
Jestli si zběhlý v práci s composerem, doporučuju mrknout na vlastní repozitář cestou na disku ( https://getcomposer.org/…ositories.md#path ), díky tomu bys měl být schopnej nainstalovat si administraci jako běžnou závislost.
Potom se ti bude hodit úprava routeru, viz kód z kdyby/console, který posílal David Matějka o pár příspěvků výše. Pravděpodobně si v rámci Administrace budeš chtít vytvořit RouteList a dát tomu jedinečný název modulu ( třeba „Admin“ :P ). Pak by sis měl nastavit mapování presenterů pro danej modul v konfiguraci application.mapping, kdy přidáš svůj pojmenovaný modul jako mapu k presenterům administrace, tj před výchozí mapování přidáš třeba
Admin: SexyAdministrace/Presenters/*Presenter
Potom routy z tý pojmenovaný RouteList budou překládaný na presentery v daným namespace.
Myslím že by to takhle mělo stačit, pokud se na něčem zasekneš nebo jsem něco nepopsal dostatečně, určo se ozvi.
- dehtak
- Člen | 113
Tak nakonec jsem to nechal jako model tu administraci.
muj boostrap
namespace App;
use Nette\Configurator;
class Bootstrap {
public static function boot(): Configurator{
$configurator = new Configurator;
$configurator->enableTracy(DIR_ROOT . '/log');
$configurator->setTimeZone('Europe/Prague');
$configurator->setTempDirectory(DIR_ROOT . '/temp');
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->addDirectory(realpath(DIR_ROOT.'/../Admin'))
->register();
$configurator->addConfig(DIR_ROOT . '/config/common.neon');
$configurator->addConfig(DIR_ROOT . '/config/local.neon');
$configurator->addConfig(DIR_ROOT . '/../Admin/config/admin.neon');
return $configurator;
}
}
potreboval bych udelat nakou fabriku na detekovani Modelu. neco jako
getModelName podle toho jakej modej je zrovna nacten.
Ale z ceho to vytahnout? Mimochodem ten extesions sem vzdal v tom se vubec
nevyznam.
Editoval dehtak (29. 4. 2020 15:08)
- Toanir
- Člen | 57
Týjo… to s tím RobotLoaderem vypadá šikovně :) Mě to nenepadlo, páč se RobotLoaderu vyhejbám jak čert kříži a opírám se o autoloading z composeru.
Máš to dělaný tak, že každá z těch aplikací má vlastní bootstrap a vlastní konfiguráky? Jeslti jo, mohl bys ten model nasypat rovnou do konfigurace podle který bys volal/vytvářel servisky z Administrace. Pak by to mohlo vypadat tak že bys měl
# app1/config/common.neon
parameters:
applicationModel: "Money stuff"
# app2/config/common.neon
parameters:
applicationModel: "Very household"
# administration/config/common.neon
services:
- Administration/AppModel/AppModelFacade(%applicationModel%)
Jinak z těch extension si nedělej těžkou hlavu… V podstatě slouží
k pohodlnýmu zabalení funkcionality a drátování do úhlednýho drop-in
balíčku a to zadrátování potom vypadá naprosto libově…
Většinu věcí co se týče businessu bys měl dokázat i bez nich.
- dehtak
- Člen | 113
Kazda aplikace ma svuj boostrap krome teda admina. To co mi navrhujes nemuzu
pouzit, ja prave potrebuju detekovat Front Modul od Admin modul.
Kazdej web ma front modul a admin modul.
Prave potrebuju tu fabricku abych mohl par veci oddelit ktere bych potreboval. Dejme tomu ze budu mit translator a jazyky pro admina ve slozce Admin/lang. Aplikacce treba translator mit vubec nebude. Diky ty fabricce si zjistim jakej je nactenej modul a pak tomu translatoru podle toho predam slozku kde ma hledat jazykovy soubory.
Editoval dehtak (29. 4. 2020 18:17)
- Toanir
- Člen | 57
Hmm, takže detekuješ modUl a ne modEl? :P
Detekci modulu bys imho měl řešit už u routeru, kde si zaregistruješ routy pro admin modul souběžně s ostatníma… Mohlo by to potom vypadat nějak následovně:
// web1/app/Routing/RouterFactory.php
namespace App\Routing;
class RouterFactory {
private $adminRouter;
public function __construct(IRouter $adminRouter) {
$this->adminRouter = $adminRouter;
}
public function create(IRouter $adminRouter) {
$routes = new \Nette\Application\Routing\RouteList();
$routes[] = $this->adminRouter;
$routes[] = $this->createAppRoutes();
return $routes;
}
private function creteAppRoutes() {
$routes = new RouteList('Front');
$router->addRoute('<presenter>/<action>', ...);
return $router;
}
}
//Admin/src/Routing/RouterFactory
namespace Admin\Routing;
class RouterFactory {
public static function createRouter() {
$routes = new \Nette\Application\RouteList('Admin');
$routes->addRoute('admin/<presenter>/<action>', ...);
return $routes;
}
}
a v konfigu to pak akorát zadrátuješ
services:
routerFactory: App\Routing\RouterFactory(Admin\Routing\RouterFactory::create())
router: @routerFactory::create
Nezapomeň, že pro moduly musíš mít nstavený application.mapping viz pŕedchozí příspěvek.
- dehtak
- Člen | 113
To je vytvoreni routru trosku jinak, ja ho mam takhle
namespace App\Factory;
use Nette;
use Nette\Application\Routers\RouteList;
final class Router
{
use Nette\StaticClass;
public static function create(): RouteList{
$router = new RouteList;
$router->withModule('Admin')
->addRoute('admin/<presenter>/<action>[/<id>]', 'Home:default');
$router->withModule('App')
->addRoute('<presenter>/<action>[/<id>]', 'Home:default');
return $router;
}
}
Nejak sem z toho tvyho routru nepochopil jak si detekuju modul.
Nebo me tak jeste napadlo on by se nemusel detekovat modul stacilo by aby si
kazdej modul nacet config sam pro sebe aby nebyly slouceny. To by bylo asi tak
nejlepsi. Mimimochodem jestli sem psal nekde model tak se omlouvam me uz se to
vsechno plete.
Editoval dehtak (30. 4. 2020 13:59)
- Toanir
- Člen | 57
Hehe,, s modulem to všechno dává větší smysl :)
V mým příkladu je to akorát rozházený do různejch tříd a svázaný skrze DI. Mělo by to dělat vesměs to samý jako tvoje ukázka. Já název modulu předávám konstruktorem a ty pro to využíváš fluentní skládání.
Jestli tvůj router vypadá takhle, měl bys mít vystaráno.. alespoň v části routeru. V zachycenejch routách bys měl mít v Requestu parametr module vedle parametrů presenter a action a vlastně všech dalších parametrů, který ti router zachytává. Jak s ním chceš teď naložít? Respektive jaká je teď tvoje situace? Načte se ti presenter z administrace?
Jen pro shrnutí probublání požadavku aplikací vypadá zhruba nějak tahke:
- HttpRequest se prožene vytvořeným routerem, při matchnutí se vytvoří (aplikační) Request, který obsahuje všechno, co dostane od routeru
- Na základě nakonfigurovanýho application.mapping a parametru presenter (a případně module) se vytvoří Presenter
- Presenter zchroupe odpověď a vrací (aplikační) Response díky logice, co do něj nacpeš, a čassto díky Latte
- Aplikace si zmanažuje Response a odesílá HttpResponse
- dehtak
- Člen | 113
tak jsem to udelal takhle nevim jestli je to dobre
use Nette\Application\Application;
class Modul {
private $modul;
private $modulDir;
public function __construct(Nette\Application\Application $app){
$request = $app->getRequests();
$name = $request[0]->getPresenterName();
$pos = strrpos($name, ':');
$this->modul = substr($name, 0, $pos);
$this->modulDir = $this->modul=='App' ? realpath(DIR_ROOT.'/App') : realpath(DIR_ROOT.'/../'.$this->modul);
}
}
v configu mam tohle
services:
modul: Modul
Editoval dehtak (30. 4. 2020 23:33)
- Toanir
- Člen | 57
@ autoloading, jj na nových projektech se opírám pouze na PSR-4 a zároveň se snažím dělat moduly co nejmělčí moduly což mě ve výsledku nutí dávat věci tam, kam patří. :P
@ Modul tady šaháš už na dost věcí. Teoreticky vzato by to mělo fungovat ve většině případů. Průšvih můźe nastat, pokud budeš dělat například forward do jinýho modulu, pak budeš vázanej na modul ve kterým byl první request. Aby tohle fungovalo vždy, zabal to do funkce, která vždy vezme poslední request a podle toho se bude orientovat, tj tvoje třída by mohla vypadat takhle:
class Modul {
private $application;
public function __construct(Nette\Application\Application $app){
$this->application = $app;
}
public function getModuleDirForCurrentRequest() {
$moduleName = $this->getModuleNameOfCurrentRequest();
return $this->getModuleDirectory($moduleName);
}
private function getModuleNameOfCurrentRequest() {
$request = $this->application->getRequests();
$name = end($request)->getPresenterName();
$pos = strrpos($name, ':');
return substr($name, 0, $pos);
}
private function getModuleDirectory(string $module) {
return $module =='App' ? realpath(DIR_ROOT.'/App') : realpath(DIR_ROOT.'/../'.$module);
}
}
Dovolil jsem si ukázku rozsekat na kratší metody s exlicitním pojmenováním aby bylo úplně jasný, co dělají… Celkově mi to ale připadá trošičku pochybný a asi není úplně košér takhle pracovat s aplikací.
Stále jsem úplně nepochopil, co s tím adresářem chceš vytvářet. Můžeš to nějak blíže nastínit? Třeba pro tvůj problém existuje jednodušší řešení
Editoval Toanir (1. 5. 2020 19:36)
- dehtak
- Člen | 113
ja uz sem to vyresil uplne jinak, prez htaccess jak mi radily na zacatku. Ted to mam jako samostatnou aplikaci vyresil jsem i nacteni db configu od apllikaci. Uz to dal resit nebudu. Dlouho sem se nad tim trapil. Pokud chces vedet jak tak to sem muzu hodit.
Editoval dehtak (1. 5. 2020 21:56)