Router

V tuto chvíli již máte celkové povědomí o tom jak Jet MVC funguje, víte co je báze, co je stránka a kontroler. Jeden z posledních dílků co schází do úplnosti skládačky je router.

A hned na začátek jedna důležitá informace. Router hlavně vyhodnocuje. Na základě URL rozhodne o jaký požadavek se jedná (o jakou bázi,lokalizaci, stránku a jak bude naloženo s případným zbytkem URL) a nastaví celkový stav. Ale router již neprovádí nic jako posílání http hlaviček, generování výstupu a tak dále. Ne, to není práce pro router. Abych byl přesný, tak router musí provést věci, které jsou součástí resolv procesu - tedy zavolat inicializer báze, nastavit lokalizaci a překladač. To je nutná část vyhodnocovacího procesu. Ale již nepošle na výstup vygenerovanou stránku. To již routeru nepřísluší.

V praxi se děje to, že se v systému vytvoří singleton třídy Jet\MVC_Router (nebo jiné - vaší implementace, pokud to určíte pomocí továrny) a následně se vyhodnotí URL, kterou obdrží jako parametr (může tedy jít o jakoukoliv URL, ne pouze tu z aktuálního http požadavku).

Router provede analýzu / vyhodnocení této URL (zjistí o jakou bázi, lokalizaci a stránku se jedná) a nastaví svůj vnitřní stav a stav systému (například aktuální lokalizaci).

Až pak následuje proces, kdy se na základě zjištěných informací (vnitřního stavu routeru) skutečností provádí činnost, která fakticky znamená poslání odpovědi na http požadavek.

A i když činnost provedená na základě vyhodnocení není integrální součástí routeru, tak je to činnost na routeru přímo závislá a dobře to demonstruje co vše router vyhodnotí. Tento poslední krok najdete ve třídě Jet\Application, metodě runMVC().

Metoda Application::runMVC()

Možná jste se pozastavili nad tím co tu najednou dělá třída Jet\Application, když se bavíme o MVC. Jak bylo výše uvedeno, tak router pouze vyhodnocuje URL a nastavuje potřebný stav.

Ukažme si to na příkladu. Router zjistí zda se náhodou nejedná o přesměrování. Tedy zjistí, že daná URL je sice platná, ale má směřovat jinam (teď neřešme z jakého důvodu). Ale jak to přesměrování bude ve finále provedeno? Tedy kdo, co a jak pošle potřebné http hlavičky? A budou doopravdy http hlavičky odeslány? To už není věc MVC, ale čistě věc vaší aplikace. Ano, ve většině případů stačí poslat hlavičky a hotovo. Ale co když vám o přesměrování nejde, ale chcete třeba náhled stránky pro vaše CMS? Nebo co když je při přesměrování třeba provést nějakou operaci, kterou Jet sám o sobě neumí? 

A další příklad: Co takhle stránka, která vyžaduje přihlášení a ověření práv. Jistě, v Jet existuje standardní způsob jak to obsloužit a ten si ukážeme dále. Ale opět nikde není psáno, že to ve vaší aplikaci musí být řešeno právě tak, jak to Jet dělá standardně. To by vás omezovalo a bralo vám to svobodu a manévrovací prostor.

Právě z těchto důvodů je činnost vykonávaná na základě zjištění routeru zcela separovaná od MVC a vlastně náleží do aplikačního prostoru. V Jet je k dispozici výchozí implementace obsloužení celé posloupnosti zpracování, která by měla být pro většinu situací dostačující - to je právě metoda Application::runMVC(), která je volána z ~/application/bootstrap.php. Ovšem uspořádání dává jasně najevo, že si můžete implementovat svou vlastní posloupnost a logiku konečného zpracování požadavku.

A pro názornost bude úplně nejlepší se na tuto jednoduchou metodu rovnou podívat:

public static function runMVC( ?string $URL null ): void
{
    
Debug_Profiler::blockStart'MVC router - Init and resolve' );

    
$router MVC::getRouter();

    
$router->resolve$URL );

    
Debug_Profiler::blockEnd'MVC router - Init and resolve' );

    if( 
$router->getIsRedirect() ) {
        
Http_Headers::redirect(
            
$router->getRedirectType(),
            
$router->getRedirectTargetURL()
        );
    }

    if( 
$router->getHasUnusedUrlPath() ) {
        
Http_Headers::movedPermanently$router->getValidUrl() );
    }


    if( 
$router->getIs404() ) {
        
ErrorPages::handleNotFoundfalse );

        return;
    }

    
$base $router->getBase();
    
$locale $router->getLocale()
    
$page $router->getPage();


    if( !
$base->getIsActive() ) {
        
ErrorPages::handleServiceUnavailablefalse );
        return;
    }

    if( !
$base->getLocalizedData$locale )->getIsActive() ) {
        
ErrorPages::handleNotFoundfalse );
        return;
    }

    if( !
$page->getIsActive() ) {
        
ErrorPages::handleNotFoundfalse );
        return;
    }

    if(
        
$page->getSSLRequired() &&
        !
Http_Request::isHttps()
    ) {
        
Http_Headers::movedPermanentlyHttp_Request::URL
            
include_query_stringtrue
            
force_SSLtrue 
        
) );
    }


    if( 
$router->getLoginRequired() ) {
        
Auth::handleLogin();
        return;
    }

    if( 
$router->getAccessNotAllowed() ) {
        
ErrorPages::handleUnauthorizedfalse );

        return;
    }

    
$result $page->render();

    
$page->handleHttpHeaders();

    echo 
$result;
}

Z kódu by mělo být patrné jak konečné zpravování standardně probíhá. Ale pár důležitých věcí je třeba zdůraznit.

  • Router je singleton, jehož instanci drží třída Jet\MVC. Tedy router nesmí být někde ve vzduchoprázdnu například jako globální proměnná a také musí vždy existovat právě jedna aktivní instance routeru. Jet stejně jako vaše aplikace s routerem pracuje - používá jej. Je to tedy klíčové.
  • Je vidět, že na rozhodovací proces (resolv) je vytvořen blok pro profiler. Rozhodovací proces musí být rychlý. Ten blok je tedy velice důležitý.
  • A s dovolením ještě jendou připomenu, že toto vše si můžete v aplikačním prostoru udělat jak chcete vy. Nehodí se se vám například výchozí strategie v situaci kdy je třeba jazyková mutace neaktivní? Vůbec nic vám nebrání si udělat svou posloupnost a svou vlastní metodu runMVC.

Ještě než se vrhneme na router samotný, tak je nutné si něco říct o třídě Jet\MVC. A následně už můžete blíže prozkoumat třídu Jet\MVC_Router.

Předchozí kapitola
Jet\MVC_Controller_Router_AddEditDelete
Další kapitola
Jet\MVC_Router