Symfony po krůčkách – Routing

Hezké URL jsou ve světě webových aplikací v dnešní době již v podstatě nutností. Dnešní díl přivádí pod světla ramp Symfony komponentu Routing, díky které je práce s hezkými URL a jejich správa opravdu jednoduchá a elegantní. Dnes si ukážeme základní principy routování v Symfony.
Seriál: Symfony po krůčkách (18 dílů)
- Symfony po krůčkách – Event Dispatcher 30. 11. 2015
- Symfony Console jako první rande se Symfony 7. 12. 2015
- Symfony po krůčkách – Filesystem a Finder 14. 12. 2015
- Symfony po krůčkách – Paralýza možností? OptionsResolver tě zachrání 21. 12. 2015
- Symfony po krůčkách – spouštíme procesy 4. 1. 2016
- Symfony po krůčkách – Translation – překlady jednoduše 11. 1. 2016
- Symfony po krůčkách – Validator (1) 18. 1. 2016
- Symfony po krůčkách – Validator (2) 25. 1. 2016
- Symfony po krůčkách – Routing 1. 2. 2016
- Symfony po krůčkách – MicroKernel 9. 2. 2016
- Konfigurujeme Symfony pomocí YAMLu 16. 2. 2016
- Symfony po krůčkách – oblékáme MicroKernel 23. 2. 2016
- Symfony po krůčkách – ClassLoader 29. 2. 2016
- Symfony po krůčkách – Twig 8. 3. 2016
- Symfony po krůčkách – Twig II. 15. 3. 2016
- Symfony po krůčkách – DomCrawler a CssSelector 23. 3. 2016
- Symfony po krůčkách – HTTP fundamentalista 12. 4. 2016
- Symfony po krůčkách – ušli jsme pořádný kus 19. 4. 2016
Routing nám slouží ke 2 základním úkolům:
- Na URL namapuje pojmenovanou sadu konfiguračních parametrů (tzv. routa), podle kterých může aplikace provést konkrétní akce. (Např.
'marketing/article/new' => 'article_new'
). - Na základě routy generuje URL. (Tzn. opačný směr
'article_new' => 'marketing/article/new'
).
Příklad na začátek
Komponentu lze nainstalovat pomocí Composeru:
composer require symfony/routing
Pro úplný základ routování jsou potřeba 3 části:
RouteCollection
– obsahuje kolekci rout (routa je představována třídouRoute
).RequestContext
– obsahuje informace o aktuálním requestu.UrlMatcher
– provádí mapování requestu na konkrétní routu.
Jak spolu jednotlivé části fungují, lze vidět na jednoduchém příkladu:
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
require_once __DIR__ . '/vendor/autoload.php';
$route = new Route('/hello', ['controller' => 'GreetingController']);
$routeCollection = new RouteCollection();
$routeCollection->add('greeting', $route);
$requestContext = new RequestContext('/');
$urlMatcher = new UrlMatcher($routeCollection, $requestContext);
$parameters = $urlMatcher->match('/hello');
var_dump($parameters);
// ['controller' => 'GreetingController', '_route' => 'greeting']
Stačí nám 3 důležité třídy
Route – co kam vede
Třída Route
přebírá jako první parametr v konstruktoru textový řetězec obsahující část URL za doménou, tzv. URL path. Jako druhý parametr se předává pole proměnných, které může obsahovat cokoliv, co logika vaší aplikace vyžaduje ke zpracování požadavku. Zde je kupříkladu definován kontrolér, protože Symfony stojí na MVC architektuře a aplikace potřebuje vědět, který kontrolér se má o požadavek postarat.
RouteCollection – když je jich víc
Pomocí metody RouteCollection::add()
lze do kolekce přidávat libovolné množství rout. Metoda má dva argumenty, první je název routy, druhý je instance třídy Route
.
UrlMatcher – volba té pravé
Metoda UrlMatcher:match()
pak hledá routu na základě URL a pokud takovou nalezne, vrací pole parametrů dané routy rozšířené o její název pod klíčem _route
. Pokud není nalezena žádná odpovídající routa, je vyhozena výjimka ResourceNotFoundException
a my můžeme uživateli vrátit například 404 stránku.
Vytváříme Routu
Nejčastěji budete pravděpodobně využívat první 2 argumenty konstruktoru:
- na prvním místě URL path, která může obsahovat placeholdery pro dynamickou část tvořenou parametry routy (např.
article/edit/{articleId}
) - na druhém místě se pak nastavuje pole výchozích hodnot, které je vráceno v případě, že request odpovídá dané routě
$route = new Route('/hello', ['controller' => 'GreetingController']);
Zajímavý je poslední parametr $condition
– podmínka, která musí být vyhodnocena jako pravdivá, aby byla routa rozpoznána. K čemu slouží ostatní parametry, lze nastudovat v dokumentaci.
Vytváříme RequestContext
RequestContext
má v sobě informace o aktuálním requestu, které můžeme definovat pomocí parametrů konstruktoru. Všechny potřebné údaje lze získat z globální proměnné $_SERVER
, ale elegantnějším řešením je použití Symfony komponenty HttpFoundation
a její třídy Request
. RequestContext
pak vytvoříme následujícím způsobem:
use Symfony\Component\HttpFoundation\Request;
$context = new RequestContext();
$context->fromRequest(Request::createFromGlobals());
Generujeme URL
Symfony poskytuje jednoduchý nástroj pro generování URL pro danou routu, a tím je třída UrlGenerator
. Jeho použití je opravdu přímočaré:
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
require_once __DIR__ . '/vendor/autoload.php';
$routes = new RouteCollection();
$routes->add('article_edit', new Route('/article/edit/{articleId}'));
$context = new RequestContext('/');
$generator = new UrlGenerator($routes, $context);
$url = $generator->generate('article_edit', ['articleId' => 1]);
var_dump($url);
// /article/edit/1
Metoda UrlGenerator::generate()
přebírá:
- 1. parametr název routy,
- na 2. místě pole parametrů
- a 3. parametrem si můžeme určit, zda chceme generovat cestu absolutní nebo relativní.
Další způsoby definování rout
Už jsme si ukázali, že routy do kolekce můžeme přidávat pomocí metody RouteCollection::add()
. To ale rozhodně není jediný způsob. Podívejme se na další možnosti, jak definovat routy v naší aplikaci:
- Definice v souboru – routy můžeme definovat v konfiguračních yml nebo xml souborech. Definice routy v yml může vypadat např. takto:
# routes.yml
article_edit:
path: /article/edit/{articleId}
defaults: { _controller: ArticleController::editAction }
requirements:
articleId: \d+
Pro načtení definice využijeme YamlFileLoader
. Aby tento příklad fungoval, je potřeba mít nainstalované Symfony komponenty Config
a Yaml
(composer require symfony/config symfony/yaml
).
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;
require_once __DIR__ . '/vendor/autoload.php';
$locator = new FileLocator(__DIR__);
$loader = new YamlFileLoader($locator);
$routeCollection = $loader->load('routes.yml');
- Routy můžeme definovat taky pomocí closure nebo anotací, pro bližší info viz oficiální dokumentace.
Jak to vše poskládat dohromady?
Jednoduše! Součástí Routing komponenty je třída Router, která vše zaobaluje a představuje tak krásný příklad integrace jednotlivých částí routovacího systému v Symfony.
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Router;
require_once __DIR__ . '/vendor/autoload.php';
$locator = new FileLocator(__DIR__);
$requestContext = new RequestContext();
$router = new Router(
new YamlFileLoader($locator),
'routes.yml',
[],
$requestContext
);
$route = $router->match('/article/edit/1');
var_dump($route);
// ['_controller' => 'ArticleController::editAction', 'articleId' => '1', '_route' => 'article_edit']
$url = $router->generate('article_edit', ['articleId' => 1]);
var_dump($url);
// '/article/edit/1'
Zase o krok dále
Dnes jsme si ukázali:
- co je to routa,
- k čemu slouží routování a jak to v Symfony funguje,
- jak generovat URL adresy,
- jakými způsoby lze definovat routy v aplikaci.
Zajímavý seriál, děkuji, doufám, že bude pokračovat.
Zeptám se: Má symfony také nějaké komponenty pro zjednodušení tvorby a zpracování datagridu a formuláře? To mě totiž většinou nejvíc pálí a mám pocit, že fw to nijak zvlášť nepodporují. Obyčejně existují nějaké externí pluginy, které ne vždycky fungují, různé paginatory např., ale kompletní datagrid s řazením apod. nic moc. Má to symfony?
Ahoj, muzu doporucit https://github.com/kitpages/KitpagesDataGridBundle nebo https://github.com/APY/APYDataGridBundle :)
Vypadá zajímavě – prozkoumám to, děkuji.