Přejít k navigační liště

Zdroják » PHP » Symfony po krůčkách – Routing

Symfony po krůčkách – Routing

Články PHP

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.

Nálepky:

Routing nám slouží ke 2 základním úkolům:

  1. 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').
  2. 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:

  1. RouteCollection – obsahuje kolekci rout (routa je představována třídou Route).
  2. RequestContext – obsahuje informace o aktuálním requestu.
  3. 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');

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.

Komentáře

Subscribe
Upozornit na
guest
3 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
lenoch

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?

lenoch

Vypadá zajímavě – prozkoumám to, děkuji.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.