Kontroler (třída Jet\MVC_Controller)

Předpokládám, že jste již seznámený s principem jak Jet MVC funguje, seznámili jste se s entitami báze a stránka.

A teď je čas kouknout na kontrolery. Kontrolery již nejsou entita v rámci Jet. Není to nic jako báze a stránka. Kontrolery jsou třídy ve vašem aplikačním prostoru a může se jednat jak o samostatné třídy, tak může jít o součástí aplikačních modulů (což doporučuji).

Tyto třídy - kontrolery jsou na Jet MVC pevně navázány. Aby byla vyřešena tato návaznost, tak každý váš kontroler musí implementovat abstraktní třídu Jet\MVC_Controller, v reálné praxi však spíše budou dědit od tříd Jet\MVC_Controller_Default, Jet\MVC_Controller_REST a případně dalších, které si sami vytvoříte. K tomu se dostaneme později. Ale naprostý základ je právě abstraktní třída Jet\MVC_Controller. To je základní pojítko mezi ekosystémem Jet a vaší aplikací (vašimi moduly a třídami). Další zmíněné třídy, zejména Jet\MVC_Controller_REST, již řeší konkrétní použití - např. tvrodbu REST serveru. Vraťme se tedy k základní třídě Jet\MVC_Controller.

Jak již víte, tak instanci kontroleru a jeho volání bude zabezpečovat obsah stránky. To znamená, že se nemusíte starat o to jak se vytváří instance kontrolerů, ale je důležité se dobře orientovat v kontrolerech samotných.

Vlastnosti

S vlastnostmi kontrolerů budete běžně pracovat - zmíněné vlastnosti nejsou určené pouze pro interní účely, ale jsou určené pro využití v aplikačním prostoru. Je tedy klíčové se s nimi seznámit.

Vlastnost Význam
protected MVC_Page_Content_Interface $content Kontroler má k dispozici instanci obsahu stránky, který jej inicioval a zavolal. Tedy obsahu ke kterému kontroler náleží a může tak dle potřeby přistupovat ke všem informacím parametry obsahu počínaje, informací o bázi konče.

Tato vlastnost je vždy nastavena a dostupná.
protected ?Application_Module $module = null Pokud je kontroler použit v rámci systému aplikačních modulů, tak zde drží instanci hlavní třídy modulu. Jak již víte, tak kontrolery je možné pouźít bez modulů. Proto tato vlastnost není mandatorní.
protected MVC_View $view Toto je velice důležité. Je to instance view (tedy instance třídy Jet\MVC_View ). 

Tedy je to to co váš kontroler použije pro vygenerování výslednéko výstupu. 

Tato vlastnost je mandatorní. Ale kontroler si instanci view vytváří sám v metodě initializeDefaultView(). Tedy inicializaci view máte naprosto pod vaší kontrolou.

Kontorler nemusí view použít (viz dále). Ovšem mnohem častěji je view použito. Proto je vlastnost mandatorní.

Metody

Metoda Význam
public __construct(
MVC_Page_Content_Interface $content
)
Konstruktor ... Jak vidno, tak má jediný ale podstatný parametr - obsah stránky, který kontroler inicializuje a ke kterému náleží.
protected initializeDefaultView(
): void
Tato metoda vytváří instanci výchozího view vašeho kontroleru. 

POZOR! Zde je jeden chyták. Výchozí implementace spoléhá na to, že kontroler je součástí nějakého vašeho modulu. Pokud se rozhodnete tvořit kontrolery mimo moduly, tak je naprosto nutné tuto metodu přetížit a udělat si vlastní implementaci. Proč? Protože adresář kde jsou view skirpty se určuje podle adresáře příslušného modulu. A když je kontroler osamocen (není součástí aplikačního modulu), tak prostě neexistuje metoda jak určit cestu adresáře obsahujícího view skripty. 

Jinak je pochopitelně možné metodu přetížit kdykoliv, i když pracujete s moduly, a inicializaci view si udělat po svém.
public getContent(
): MVC_Page_Content_Interface
Vrací instanci obsahu ke kterému kontroler náleží.
public getModule(
): Application_Module|null
Pokud je kontroler součástí modulu, tak je rovněž možné přistupovat k instanci hlavní třídy modulu.
public resolve(
): bool|string
Ma metodu resolve() jsme již narazili u stránky. Tedy tato metoda přímo s metodou stránky souvisí a je to právě ta metoda, která je ve skutečnosti stránkou při resolve procesu volána.

Je to velice důležité. Pokud váš kontroler nějak zpracovává např. URL, nebo GET parametry (a na základě toho se rozhoduje co bude dělat), tak právě tuto metodu musíte implementovat a potřebnou logiku v ní pořešit.

Výchozí implementace se pokouší zjistit zda váš kontroler dává k dispozici svůj mikrorouter (instaci třídy Jet\MVC_Coutroller_Router) a pomocí něj situaci vyřešit. Ale to je již samostatné téma.

Teď je důležité to, že právě zde je místo, kde si například odchytíte URL detailu produktu na e-shopu, který právě vyvíjíte, nebo zde rozhodnete o tom, zda v administraci uživatel chce přidat nový článek, nebo naopak nějaký starý smazat. Neprovedete zde ještě onu operaci. Ne, k tomu tato metoda neslouží. Je to zatím pouze bod rozhodnutí o tom, co se bude dít dál a také bod přípravy na provedení dané operace. 

Proč přípravy na provedení operace? Protože například nic nebrání tomu si zde již natáhnout a jako vlastnost vašeho kontroleru držet instanci článku (například), který budete na základě URL zobrazovat a rovnou nastavit kontext keše a routeru říct, že daná část URL je platná.

Ještě jednou tedy zopakuji, že tato metoda je bod rozhodnutí a přípravy. A je plně ve vaší moci. Má být vámi ve vašem kontroleru implementována - tak jak potřebujete.

A pozor! Metoda může vracet jak bool,tak string. Proč?
  • Pokud vrátí true, tak to jednoduše znamená, že je vše v pořádku, nebo že váš kontroler daná situace nezajímá a nic nebude řešit. Obsah se nezmění. Resolv proces pokračuje dál.
  • V případě vrácení false říkáte, že váš kontroler narazil například na neplatnou URL, nebo z jiného důvodu požadavek je neplatný. Výsledkem má být 404, nebo nějaké jiné řešení, ale to už není věcí vašeho kontroleru - ten pouze říká, že tento požadavek je neplatný.
  • Pokud vrátí string, tak to znamená, že je vše v pořádku, ale bude se volat ta akce kontroleru, kterou kontroler určil touto návratovou hodnotou metody resolv a podle toho se také modifikuje obsah.
public dispatch(
): void
Tato metoda je již provedení (volá) konkrétní operace. To znamená, že na základě příslušného obsahu zavolá konkrétní metody kontroleru představující akci. 

Akce kontroleru je metoda s příponou _Action, nic nevrací (návratová hodnota void) a nemá žádné parametry.

Pokud někdy z nějakého důvodu budete mít potřebu toto chování změnit (např. změnit signaturu metod akcí), tak si prostě přetižte tuto metodu.
protected output(
string $view_script
): void
Toto je obvyklí a nejčastější, ale rozhodně ne jediný možný, výsledek činnosti kontroleru.

Jde o vygenerování výstupu a jeho předání obsahu stránky. Místo složitého vysvětlování si raději ukažme výchozí implementaci této metody: protected function outputstring $view_script ): void
{
    
$output $this->view->render$view_script );
    
$this->content->output$output );
}
Tedy je zavolán určený view skript a jeho výstup je předán obsahu stránky.

To pochopitelně není jediná věc,  kterou váš kontroler může udělat. Je to typická situace pro generování HTML (či textového a tak podobně) výstupu, ale nic nebrání tomu, aby kontroler udělal například toto:
  • Poslal nějaký soubor ke stažení a ukončil běh zpracování
  • Poslal data v XML, či JSON a ukončil běh zpracování
  • A tak dále ...
To co jsem právě teď uvedl vůbec nesouvisí s výstupem a metodou output. Jen chci zdůraznit, že použití metody output není povinné.

A stejně tak není povinné vygenerovat případný výstup přesně takto. Klidně můžete výstup od někde načíst, např z .html souboru a stránce jej rovnou předat: $this->content->output$my_data );
Tedy tato metoda není žádná svatá kráva. Ale v naprosto klasických a nejčastějších situacích udělá přesně to co potřebujete. Vygeneruje výstup pomocí view a vrátí jej zpět obsahu stránky (a Jet MVC se postará o sestavení stránky, jejíž součástí bude výstup daného kontroleru).

Samozřejmě opět vám nic nebrání si metodu přetížit.
public getControllerRouter(
): MVC_Controller_Router_Interface|null
Vše si rovnou vysvětlíme na příkladu: Máme aplikační modul pro administraci, který bude sloužit ke správě článků. Tedy bude přidávat, editovat, mazat, zobrazovat seznam článků ... 

Takový modul bude prakticky neustále metodou resolve vyhodnocovat co že se po něm vlastně chce a to na základě nezpracované části URL, nebo GET parametrů. V praxi je to vlastně stále se opakující kód, stále tatáž logika a je pořádná otrava dělat dvacetkrát totéž. 

Proto je v Jet k dispozici to čemu říkám mikrorouter a slouží právě pro snadnější práci s routováním a resolvingem v rámci vašeho kontroleru. Na toto téma je nutné kouknout samostatně. 

Každopádně pokud váš kontroler bude tento mikrorouter využívat, tak v této metodě je nutné vytvořit jeho instanci a mikrorouter inicializovat. Metodu resolve pak již nemusíte řešit. Jak již bylo uvedeno, tak výchozí implementace metody resolv zkouší zda je k dispozici mikrorouter - je to výchozí předpokládané chování.

Pochopitelně jsou situace, kdy není mikrorouter vhodné řešení a je tedy lepší přistoupit k přetížení metody resolv.

V ukázkové aplikaci jsou hojně zastoupena obě řešení - tedy možno nahlédnout i tam.
abstract public handleNotAuthorized(
): void;
Jsou situace, kdy je nutné reagovat na neautorizovanou / nepovolenou operaci (lidově řečeno uživatel leze kam nemá). K řešení takové situace slouží tato metoda. 

V rámci třídy Jet\MVC_Controller je abstraktní.

Ale například Jet\MVC_Controller_Default ji již implementuje a dělá to, že o situaci informuje hlavní router Jet MVC.

Naopak třída Jet\MVC_Controller_REST okamžitě reaguje posláním adekvátní odpovědi klientovi (http hlavička + chybová hláška ve formátu JSON).

Váš kontroler může neautorizované operace řešit tak jak potřebujete.

Předpřipravené kontrolery

V textu jsem již několikrát zmínil třídy Jet\MVC_Controller_Default a Jet\MVC_Controller_REST.
To jsou předpřipravené rodičovské (a tedy stále abstraktní) třídy pro vaše kontrolery. Jet\MVC_Controller_Default z nich řeší pouze jednu jedinou věc, ale Jet\MVC_Controller_REST, určená pro tvorbu REST API je již komplexnější. 

Poznámka: Vy tyto třídy můžete, ale nemusíte, používat. Můžete si ve vašem aplikační prostoru udělat své vlastní rodičovské třídy a vaše kontrolery mohou dědit od vašich vlastních tříd. Neplatí zde žádné dogma krom toho, že hlavním rodičem musí být třída Jet\MVC_Controller

Předchozí kapitola
Jet\MVC_Page_MetaTag
Další kapitola
Jet\MVC_Controller_Default