Minule jsme část o šablonovacím systému Twig zakončili tím, že jsme rozdělili původně nakódované kompletní HTML šablony tak, aby se společná část načítala ze souboru base.html.twig a jednotlivé stránky, tedy například index.html.twig a kontakt.html.twig do ní doplňovaly jen upravené části.
Mělo to a zatím má jednu nevýhodu. URL adresy v odkazech hlavního menu jsou zapsány „natvrdo“. To znamená, že v momentě, kdy změníme nějakou routu a tedy adresu stránky definovanou v souboru index.php, musíme pak jít do všech šablon, kde na tuto routu odkazujeme a vše ručně přepsat.
Seriál Silex
Automatické generování odkazu na základě názvu routy
Naštěstí Silex a Twig (podobně jako Symfony 2 a Twig) umožňují v šablonách používat speciální zápis, který na dané místo vygeneruje příslušnou adresu převzatou z definice routy. Abychom nový postup mohli začít používat, je třeba v Silexu zaregistrovat novou službu URL generator, a sice doplněním kódu:
$app->register(new Silex\Provider\UrlGeneratorServiceProvider());
Vložte jej do souboru index.php, hned za registraci Twig Service Provideru, tedy před pasáž s definicí routování.
Nyní je potřeba všem routám přidělit nějaký název, který budete v šablonách používat. Provedete to tak, že k jednotlivým definicím rout přidáte ocásek v podobě ->bind('nazev');.
Jinými slovy původní definice
$app->get('/', function() use($app) { return $app['twig']->render('index.html.twig'); });
se změní na
$app->get('/', function() use($app) { return $app['twig']->render('index.html.twig'); })->bind('home');
Po úpravě může definice URL adres v našem souboru index.php vypadat nějak takto:
Nyní už stačí upravit soubor base.html.twig, respektive všechny ostatní šablony, kde máte zapsány cesty k jednotlivým stránkám na webu, a to následovně. Tam, kde máte v HTML/Twigu zapsán odkaz, nahraďte jej tímto zápisem:
{{ app.url_generator.generate('contact') }}
Čili původní zápis odkazů v hlavním menu
<li class="first_list"><a href="/" class="main_menu_first main_current">Domů</a></li> <li class="first_list"><a href="/sluzby" class="main_menu_first">Služby</a></li> <li class="first_list"><a href="/o-nas" class="main_menu_first">O nás</a></li> <li class="first_list"><a href="/reference" class="main_menu_first">Reference</a></li> <li class="first_list"><a href="/kontakt" class="main_menu_first">Kontakt</a></li>
změníme na
<li class="first_list"><a href="{{ app.url_generator.generate('home') }}" class="main_menu_first main_current">Domů</a></li> <li class="first_list"><a href="{{ app.url_generator.generate('sluzby') }}" class="main_menu_first">Služby</a></li> <li class="first_list"><a href="{{ app.url_generator.generate('about') }}" class="main_menu_first">O nás</a></li> <li class="first_list"><a href="{{ app.url_generator.generate('reference') }}" class="main_menu_first">Reference</a></li> <li class="first_list"><a href="{{ app.url_generator.generate('kontakt') }}" class="main_menu_first">Kontakt</a></li>
Web by měl fungovat stále stejně a můžete vyzkoušet, že když změníte adresu routy, čili hned první atribut funkce $app->get(), změní se automaticky i adresy odkazů v menu.
Nastavení aktivního odkazu v menu
Používáte-li stejně jako já HTML šablonu BisLite, viz minulý díl seriálu, tak asi vidíte v navigačním menu další nedokonalost. Odkazy v menu mohou mít třídu .main_current, která způsobuje, že se odkaz v menu jeví jako podtržený. Ovšem v šabloně to máme jenom u prvního odkazu na titulní stranu. Když si načtete například kontakt, stále je podtržen odkaz domů a to není úplně nejlepší.
Nabízelo by se sice řešení, mít navigaci prostě v jednotlivých šablonách pro konkrétní stránky a tam vždy příslušnou třídu umístit k jinému odkazu menu. To by však popřelo výhody šablonování.
Místo toho se podívejme, jak v Twigu zjistit, zda se zobrazuje aktuální routa a následně přidat nebo nepřidat onu třídu. Zároveň se tím naučíme používat v Twigu zápis podmínky.
Podmínky v Twigu se zapisují následující syntaxí:
{% if nejaky_dotaz %}toto bude v html{% endif %}
Informaci o tom, jaká routa je právě načtena, získáme v Twigu vyhodnocením dotazu app.request.get('_route'). Když tedy zkombinujeme zápis podmínky s dotazem na aktuální routu a následně ji porovnáme s řetězcem, který nám vrací již známý app.url_generator.generate(), měli bychom být schopni vypsat CSS třídu jen v případě, že je načtena stránka pro daný odkaz v menu.
Není to ale úplně tak jednoduché. Dotaz app.request.get('_route') vrací informaci bez lomítka na začátku, zatímco URL generator lomítko na začátku používá. To ostatně odpovídá definicím rout.
Musíme tedy spojit dvě řetězce, tedy / a app.request.get('_route'). Ke spojování řetězců v Twigu se používá znak tilda, ~.
Dále musíme vzít v potaz výjimku, kterou představuje odkaz na titulní stranu webu. Dotaz app.request.get('_route') vrací v tuto chvíli slovo home, viz definice routování, zatímco URL generator vrací lomítko. Takže zde jen porovnáme s řetězcem home.
Výsledný zápis odkazů v menu tedy bude následující:
<li class="first_list"><a href="{{ app.url_generator.generate('home') }}" class="main_menu_first {% if app.request.get('_route') == 'home' %}main_current{% endif %}">Domů</a></li> <li class="first_list"><a href="{{ app.url_generator.generate('sluzby') }}" class="main_menu_first {% if '/' ~ app.request.get('_route') == app.url_generator.generate('sluzby') %}main_current{% endif %}">Služby</a></li> <li class="first_list"><a href="{{ app.url_generator.generate('about') }}" class="main_menu_first {% if '/' ~ app.request.get('_route') == app.url_generator.generate('about') %}main_current{% endif %}">O nás</a></li> <li class="first_list"><a href="{{ app.url_generator.generate('reference') }}" class="main_menu_first {% if '/' ~ app.request.get('_route') == app.url_generator.generate('reference') %}main_current{% endif %}">Reference</a></li> <li class="first_list"><a href="{{ app.url_generator.generate('kontakt') }}" class="main_menu_first {% if '/' ~ app.request.get('_route') == app.url_generator.generate('kontakt') %}main_current{% endif %}">Kontakt</a></li>
Zobrazení chyb v Silexu
S tím, jak postupně váš projekt roste, je tu reálné nebezpečí, že v kódu PHP, nebo častěji někde v Twigu uděláte překlep, chybu, která znemožní načtení stránky. Silex má zobrazení chyb ve výchozím stavu potlačeno. Místo nich se objeví jen hláška o tom, že se asi něco nepovedlo.
To vám ovšem během tvorby webu moc nepoví o tom, kde máte chybu. Jejich zobrazování, tedy informace o chybách podobně jako v Symfony 2, docílíte tím, že na začátek souboru index.php, hned za načtení autoloaderu, vložíte:
use Symfony\Component\HttpKernel\Debug\ErrorHandler; use Symfony\Component\HttpKernel\Debug\ExceptionHandler; // set the error handling ini_set('display_errors', 1); error_reporting(-1); ErrorHandler::register(); if ('cli' !== php_sapi_name()) { ExceptionHandler::register(); }
a po definici proměnné $app přidáte řádek:
$app['debug'] = true;
Zobrazení případného chybového hlášení už pak má vypovídající hodnotu:
Před překopírováním webu na internet samozřejmě nezapomeňte chybové hlášení zase ukrýt.
Jak přesunout Silex na hosting
Pro provozuschopný a použitelný web na mikroframeworku Silex nyní máte všechny potřebné znalosti, řekl bych. Určitě bychom se mohli dále bavit o vychytávkách v Silexu, ale o tom někdy příště.
Teď se ještě zaměřme na to, jak Silex rozběhat na nějakém reálném webhostingu. Už na začátku jsme zjistili, že Silex, podobně jako většina velkých frameworků, má oddělenu složku dostupnou z webu a složky, které obsahují programový kód nebo šablony. To není problém na serveru. Uděláte si složku pro doménu, ale webový server nasměrujete v rámci Silexu do podsložky web.
Není to problém ani na lepším hostingu. Ty vám obvykle umožní nakopírovat si souborovou strukturu aplikace a následně určit, do které z podsložek má koukat webový server. Umí to tak například hostingy používající cPanel.
Pak tu máme ale dosti početnou skupinu hostingů, které vám ani nenabídnou SSH, natož pak přístup do různých složek. Prostě dostanete obyčejné FTP a přístup do jediné složky, kam si máte web nakopírovat.
Co s tím? Asi nechcete, aby web fungoval jen tak, že bude na adrese www.domena.tld/web a nikoli i na www.domena.tld.
Řešením je změnit výchozí souborovou strukturu. Vše, co máte ve složce web prostě překopírujte o úroveň výše a složku web smaže. Následně v souboru index.php upravte cesty k autoloaderu a k šablonám pro Twig. Nic jiného jsme v našem seriálu zatím do index.php nepřidávali. Po úpravě by tedy soubor a struktura webu vypadaly následovně:
Můžete to vyzkoušet i rychle u sebe na počítači, stačí ve složce s upraveným webem spustit příkaz php -S localhost:8000 a následně do webového prohlížeče zadat adresu http://localhost:8000/.
Příště YAML a testimoniály
V minulém díle jsem vám slíbil něco o načítání souborů YAML. Dnes jsme se k němu nedostali, necháme si jej do dalšího pokračování. Vzhledem k množícím se dotazům jsem chtěl dotáhnout Twig a především ukázat, že web se Silexem můžete mít i na obyčejném hostingu.
Tvůrce webů z Brna se specializací na Drupal, WordPress a Symfony. Acquia Certified Developer & Site Builder. Autor několika knih o Drupalu.
Web Development Director v Lesensky.cz. Ve volných chvílích podnikám výlety na souši i po vodě. Více se dozvíte na polzer.cz a mém LinkedIn profilu.
Podobné články
Komentáře k článku
Jistě :) Zatím mám stále přibývající zásobu nápadů, co do dalších dílů.
Perfektní seriál! Mám jej založen už pár týdnů, ale konečně jsem se k němu dostal prakticky.
Díky. Už brzy bude další díl. O formulářích.
Ahoj,
na hostinzích, kde nelze přenastavit webroot jde nechat strukturu stejnou jako na DEV prostředí a pouzw do / doplnit .htaccess, který obstará přesměrování do požadované aplikace.
# /.htaccess
RewriteEngine on
RewriteRule ^$ web/ [L]
RewriteRule (.*) web/$1 [L]
Super seriál, díky za něj! Aspoň si opráším znalosti o Silexu. Doufám, že se dostane i na používání komponent ze Symfony... :-)