View - Jet\MVC_View

Po té co jsme se seznámili s tím jak funguje Jet MVC a víte jak požadavek projde systémem jsme konečně u view. Rovnou předesílám, že Jet nemá žádný šablonovací systém. Proč to tak je se můžete dočíst zde.

Téma view je zahrnuto pod kapitolu "Plné využití MVC v PHP Jet", ale view jako takové - tedy třída Jet\MVC_View je použitelná zcela samostatně (bez báze, stránky, routeru a toho všeho) jak si za chvíli ukážeme. Ale teď už k jádru věci.

V souvislosti s view si zavedeme termín view skript. View skript je PHP skript, ale je od ostatních skriptů jednoznačně odlišen:

  • Má vždy příponu *.phtml
  • Držím se pravidla, že jeho název vždy tvoří malá písmena a slova jsou oddělena pomlčkou, např: edit-form.phtml
    To sice není technická nutnost, ale držím se toho, aby bylo na první pohled jasné, že toto je view skript.
  • View skripty jsou v k tomu určených adresářích, které z pravidla mají název view. Najdete je v adresářích bází, v adresářích aplikačních modulů, ale i v adresářích mikroaplikací (_installer, _profiler, Jet Studio). Pojmenovat adresář takto je dobrý zvyk.
    Ovšem opět to není technická nutnost. Příkladem odlišnosti názvu adresáře view skriptů mohou být šablony mailů. Tyto šablony jsou také view skripty, ale jejich adresář se jmenuje prostě email-templates.
  • Je dobrým zvykem používat ve view alternativní - rozšířenou synaxi PHP. Tedy ne if($somethoning) {}, ale if($somethoning): endif;Je to možná o zvyku, ale závorky v tomto druhu kódu opravdu nejsou to nejpřehlednější ... Ale opět není nic co by vám nařizovalo to takto dělat. Je to doporučení - dobře míněná rada.

A nyní se již pojďme podívat jak se view v praxi používá.

Inicializace a předání dat

Samostatné použití view

Nejprve si ukážeme jak view použít zcela samostatně - tedy bez ostatních prvků MVC v Jetu. Pokud budete vytvářet modulární aplikace s bázemi a stránkami, tak tento způsob téměř používat nebudete, respektive budete jej používat minimálně (pro opravdu specifické věci). Ale je to způsob také legitimní (tedy nutno jej znát) a také se na něm lépe vysvětluje jak view funguje.

Pojďme se kouknout na ukázku samostatného použití view:

use Jet\Factory_MVC;
use 
JetApplication\Content_Article;

$article Content_Article::get$id );

$view Factory_MVC::getViewInstance(('/some/directory/');

$view->setVar('article'$article);
$view->setVar('int_param'2011);
$view->setVar('float_param'3.14);
$view->setVar('string_param''<script>alert(\'Hello!\');</script>');

echo 
$view->render('view-script-name');

Všimněte si prosím:

  • Instance třídy Jet\MVC_View není v příkladu vytvořena přímo, ale přes továrnu. Instanci Jet\MVC_View lze vytvořit i přímo, ale používat továrny je doporučeno. Použití továrny je v tomto případě silně doporučeno, ne však vyžadováno.
  • Jediný parametr konstruktoru třídy Jet\MVC_View (respektive metody Factory_MVC::getViewInstance) je úplná cesta k adresáři kde jsou umístěné view skripty.
  • Do view je možné (spíš by se dalo říct nutné) předávat data. To se dělá jednotně metodou setVar.
  • Vygenerování výstupu se provede jednoduše metodou render a výstup je vrácen jako návratová hodnota (tedy není ihned poslán na výstup aplikace). Metoda render má jediný parametr a tím je název view skriptu. Pozor! Název view skriptu bez extenze souboru, to znamená bez .phtml a také bez úplné cesty. Tedy je-li úplná cesta k view skriptu /some/directory/view-script-name.phtml, tak pouze view-script-name je název view skriptu a tedy daný parametr.

A to je z inicializace a volání view skriptu vše. Je to takto primitivní. View nemá žádné helpery, postprocesory a podobně. Přesněji řečeno takové věci i Jet měl, ale postupně jsem to odstranil jako nejednoznačné a nepřímočaré, zbytečně komplikované, generující možné nečekané situace a v konečném důsledku tedy kontraproduktivní. Tato jednoduchost se mi prostě osvědčila lépe.

Použití view v rámci kontroleru

A teď se podíváme jak je view použito v kontrolerech a tím pádem i v aplikačních modulech. Princip je stále tentýž. Jsou pouze tyto rozdíly:

  • Instanci view si nemusíte vytvářet. Tu má kontroler již nachytanou.
  • Výstup z view je nutné předat zpět obsahu stránky. Cílem je totiž umístit vygenerovaný výstup / obsah na patřičné místo v layoutu.
  • Mezi kontrolerem a view je propojení. Kontroler drží instanci view a view si drží instanci kontroleru.
Pro názornost vezměme jednu akci kontroleru. A vezmeme si něco reálného, kód z ukázkové aplikace se kterou je Jet distribuován. Z modulu Content.Articles.Browser, kontroleru Main vezmeme akci detail, jejíž účelem je zobrazit detail článku (když na něj "kliknete").

public function detail_Action(): void
{
    
$article $this->article;

    
// Navigation_Breadcrumb::addURL( $article->getTitle() );

    
$this->view->setVar'article'$article );

    
$this->output'detail' );
}

Je patrné, že:

  • Instance view je již k dispozici jako vlastnost kontroleru.
  • Pro výstup se nepoužívá metoda view->render, ale metoda kontroleru output. Tato metoda má stejně jako metoda render jediný parametr a to název view skriptu. Metoda view skript zavolá. Ovšem krom toho se také postará o předání výstupu zpět stránce za účelem jeho zařazení na správné místo v layoutu.

Poznámka: Pokud budete potřebovat například pro generování dílčí části výstupu v modulu zavolat view z úplně jiného adresáře (například nějaké univerzální view, ne z daného modulu a podobně), tak můžete použít způsob přes vytvoření instance třídy Jet\MVC_View (respektive použití továrny). Tedy například view skript modulu může klidně volat další view skript, který je součástí báze. Ve skutečnosti se to tak dělá například při generování formulářů a UI. To že již jedno view máte k dispozici (v kontroleru) neznamená, že si nemůžete nachystat a použít další view a výstup z jednoho view zařadit do výstupu view jiného. Zde nejsou žádná omezení.

View skript

Už víme jak view inicializovat a předat skriptu data a parametry a view skript zavolat - tedy vygenerovat výstup. Teď se podívejme jak takový view skript vypadá:

<?php
use Jet\MVC_View;
use 
JetApplication\Content_Article;
/**
 * @var MVC_View $this
 * @var Content_Article $article
 */

$article $this->getRaw'article' );
?>

Int: <?=$this->getInt('int_param');?><br>
Float: <?=$this->getFloat('float_param');?><br>
Bool: <?=$this->getBool('bool_param') ? 'yes' 'no';?><br>
Escaped string: <?=$this->getString('string_param');?><br>

<br>

<?php if($article): ?>
    <div>
        <?= Tr::_'Date:' ); ?>
        <?= Locale::dateAndTime$article->getDateTime() ); ?>
    </div>
<?php endif; ?>

A opět si pár věcí vypíchneme:

  • V samotném view skriptu je instance view (tedy třídy Jet\MVC_View do které jsme předali data) přítomna jako $this. Tedy to co jste v kontroleru nastavovali máte k dispozici v této instanci a pro data si můžete / máte "sáhnout" pomocí příslušných metod.
  • K předaným parametrům (datům) nepřistupujete přímo, ale přes gettery, které musí respektovat očekávaný typ daného parametru. Například pokud chcete řetězec (string), tak je jeho hodnota rovnou "prohnána" přes htmlspecialchars. Pokud chcete int, dostanete vždy int a tak dále.
  • Můžete volat co potřebujete, není žádné omezení. Tedy je potřeba překladač? Zavoláte si jej: Tr::_(). Potřebujete naformátovat datum? Není problém ... Prostě voláte přímo a jednoduše co potřebujete.
  • ... ale jsem si jistý, že tady z nikoho vás nenapadne řešit aplikačni logiku, zachytávat vstupy a kouzlit s SQL. Ano, jde to. Ale je to špatně. Ovšem proč všem zakazovat zapalovač, díky kterému si můžete rozdělat oheň a ohřát se, jen pro to, že někdo je schopen zapalovačem podpálit dům ... Je na vaší odpovědnosti aby ve view bylo jen to co tam má být a já nepochybuji o tom, že každý profesionál tu odpovědnost má.
Pro úplnost se prosím koukněte na seznam metod, které tříd Jet\MVC_View má. Tam jistě ještě pár užitečných detailů najdete.

Metody třídy Jet\MVC_View

Metoda Význam
public __construct(
string $scripts_dir
)
Jediným parametrem konstruktoru je absolutní cesta k adresáři obsahujícímu view skripty se kterými bude instance pracovat.
public setController(
MVC_Controller $controller
) : void
Pokud instanci view zakládá kontroler, tak pomocí této metody do něj vloží svou instanci.
public getController(
): MVC_Controller|null
Pokud je instance view založena kontrolerem, tak tato metoda vrátí instanci příslušného kontroleru.
public setVar(
string $key, mixed $val
): void
Nastaví parametr, který bude předán view skriptu.
public unsetVar(
string $key
): void
Zruší předávaný parametr.
public getInt(
string $key,
int $default_value = 0
): int
Vrátí hodnotu parametru vždy jako int.

Nebo výchozí hodnotu, pokud parametr není specifikován.
public getFloat(
string $key,
float $default_value = 0.0
): float
Vrátí hodnotu parametru vždy jako float.

Nebo výchozí hodnotu, pokud parametr není specifikován.
public getBool(
string $key,
bool $default_value = false
): bool
Vrátí hodnotu parametru vždy jako bool.

Nebo výchozí hodnotu, pokud parametr není specifikován.
public getString(
string $key,
string $default_value = ''
): string
Vrátí hodnotu parametru jako řetězec, který ovšem vždy zakóduje pomocí Data_Text::htmlSpecialChars.

Nebo výchozí hodnotu, pokud parametr není specifikován..
public getRaw(
string $key,
mixed $default_value = null
): mixed
Vrátí hodnotu parametru bez zásahů - přesně v té podobě jak byl parametr nastaven kontrolerem.

Kdy to použít:
  • Pokud předáváte instanci nějakého objektu.
  • Pokud předáváte pole (a víte, že obsahuje bezpečná data).
  • Pokud předáváte řetězec, který může a bude obsahovat HTML a je tedy záměr něco takového vypsat. Příklad? Tak například text článku.
public varExists(
string $key
): bool
Ověří zda je daný parametr definován.
public getScriptsDir(
): string
Vrátí absolutní cestu k adresáři obsahujícím view skripty.
public setScriptsDir(
string $scripts_dir
): string
Nastaví absolutní cestu k adresáři obsahujícím view skripty.
public getScriptName(
): string
Vrátí název view skriptu, který má být (nebo aktuálně je) renderován.
public setScriptName(
string $script_name
): string
Nastaví název view skriptu, který má být renderován.
public getScriptPath(
): string
Vrátí kompletní absolutní cestu k view skriptu.
Předchozí kapitola
Jet\MVC
Další kapitola
Layout - Jet\MVC_Layout