Symfony po krůčkách – HTTP fundamentalista

Stěžejní Symfony komponentou je HttpFoundation. Bere si na mušku naprostý základ webových aplikací – HTTP protokol. Je skvěle napsaná a snadno se používá. V dnešním díle si ukážeme, jak nám s použitím HttpFoundation knihovny aplikace pěkně prokoukne.
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
Nálepky:
Od PHP k Symfony
Napsat webovou aplikaci v čístém PHP je snadné, ale bohužel nepohodlné a často se u toho naseká mnoho chyb. Data od uživatele musíme číst z několika superglobálních polí $_GET
, $_POST
, $_COOKIE
, $_FILES
a $_SESSION
. K poslání odpovědi je třeba vypsat text a nastavit HTTP hlavičky
echo sprintf('Hello %s!', $_GET['name']);
header('Content-Type: text/html; charset=utf-8');
Pokud si zkusíme takto jednoduchý příklad, moc dobře nepořídíme. PHP zobrazí chybové hlášení Warning: Cannot modify header information - headers already sent
, protože HTTP hlavičky se musí nastavit dříve než cokoliv vypíšeme. Další chyby a problémy vyvstanou ve chvíli, kdy začneme zpracovávat soubory, parsovat HTTP hlavičky a budeme chtít psát čistý a testovatelný kód.
Všechny uvedené problémy řeší Symfony komponenta HttpFoundation. Je tak dobrá, že ji používá nejen Symfony framework, ale také Drupal, Laravel, eZ Publish a další. Nabízí skvělé objektové rozhraní, snadno se používá, přesně implementuje HTTP protokol a dokonce způsobila malou revoluci. Díky ní se Symfony neoznačuje jako MVC či MVP framework, ale honosí se titulem HTTP framework. Princip fungování Symfony aplikace je znázorněno na následujícím obrázku:
Komunikace mezi klientem a serverem pomocí HTTP protokolu
První příklad
Pojďme si komponentu HttpFoundation vyzkoušet. Nainstalujeme ji přes Composer
composer require symfony/http-foundation
Jak přepsat úvodní příklad pomocí komponenty HttpFoundation? Velmi jednoduše. Uděláme jen přesně to, co po nás chce HTTP protokol a co je uvedeno na obrázku.
<?php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
require_once __DIR__.'/vendor/autoload.php';
$request = Request::createFromGlobals();
$response = new Response(sprintf('Hello %s!', $request->query->get('name')));
$response->send();
Vytvoříme objekt $request
, který reprezentuje HTTP požadavek od klienta. Potom vytvoříme objekt $response
, který představuje HTTP odpověď, a zavoláme na něm metodu send()
, která tuto odpověď pošle klientovi. A to je vše!
Request – HTTP požadavek
Objekt třídy Request
zapouzdřuje všechna superglobální PHP pole s uživatelskými vstupy. Nejjednoduší způsob, jak jej vytvořit, je pomocí helperu
$request = Request::createFromGlobals();
Můžeme použít i zápis, z kterého na první pohled vidíme, co se přesně stane
$request = new Request($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER);
A jelikož Symfony myslí na všechno, tak objekt $request
lze vytvořit i z obyčejné URL adresy a parametrů
$request = Request::create(
'https://spazef0rze:1234@example.org:443/admin?action=edit',
'POST',
['title' => 'Test']
);
Všechna data jsou dostupná přes veřejné atributy třídy Request
$request->query; // $_GET
$request->request; // $_POST
$request->cookies; // $_COOKIE
$request->files; // $_FILES
$request->server; // $_SERVER
$request->headers; // $_SERVER['HTTP_...']
Symfony nejde jen o skvěle použitelné API, ale také o rychlost. S těmito daty pracujeme v aplikaci nejčastěji, a proto jsou dostupné jako třídní atributy, ke kterým PHP přistupuje daleko rychleji než k metodám.
Data nejsou uložena v obyčejném poli, ale jsou zapouzdřena v objektech třídy ParameterBag
. Ta obsahuje spoustu užitečných metod, které nám ušetří psaní zbytečného kódu:
Uložení HTTP dat v třídě Request z HttpFoundation komponenty
$request->query->all(); // $_GET
$request->query->get('action', 'list'); // array_key_exists($_GET, 'action') ? $_GET['action'] : 'list'
$request->cookies->has('PWID'); // isset($_COOKIE['PWID']);
$request->request->keys(); // array_keys($_POST)
Navíc můžeme uživatelská data snadno filtrovat:
$request->query->getInt('id'); // převede $_GET['id'] na číslo
$request->query->getAlpha('action'); // z $_GET['action'] odstraní znaky, které nejsou v abecedě
$request->query->getDigits('order'); // z $_GET['order'] odstraní nečíselné znaky
$request->request->filter('email', null, FILTER_VALIDATE_EMAIL);
// vrátí hodnotu z $_POST['email'] pokud obsahuje validní email
Kdo v čistém PHP psal REST API, ví, jak složitě se dostávájí z POST pořadavku data (např. JSON řetězec). Třída Request
na to má metodu
$content = $request->getContent();
Práci s daty máme skvěle zvládnutou. Tím možnosti komponenty HttpFoundation nekončí. O HTTP požadavku poskytuje veškeré informace. Pro představu zmíním pár metod:
$request->isSecure(); // HTTPS protokol?
$request->getMethod(); // název HTTP metody
$request->isMethod('POST'); // odesláno přes POST?
$request->isMethodSafe(); // posláno přes GET nebo HEAD?
$request->isXmlHttpRequest(); // AJAX
$request->isNoCache(); // je nastavena hlavička no-cache?
$request->getLanguages(); // podporované jazyky prohlížeče
$request->getCharset();
$request->getEncodings();
$request->getAcceptableContentType();
$request->getPathInfo(); // významná část URL adresy nutná pro routování
Response – HTTP odpověď
Objekt třídy Response
obsahuje veškeré informace nutné k poslání odpovědi. Zkrátka, nic jiného k vykreslení webové stránky není potřeba. Vytvořit odpověď je snadné
use Symfony\Component\HttpFoundation\Response;
$response = new Response('Hello World!');
// nebo se všemi argumenty
$response = new Response('Hello World!', Response::HTTP_OK, ['content-type' => 'text/html'];
Největší výhodou tohoto přístupu je, že se neovlivňují globální proměnné, nenastavují žádné hlavičky a neposílá se obsah. Takto vytvořenou odpověď můžete kdekoliv v aplikaci zahodit a vytvořit novou. Nic se tím nepokazí. Vytvořenou odpověď lze upravovat:
$response->setContent('Hello Martin!');
$response->setStatusCode(Response::HTTP_NOT_FOUND); // vrátí 404
$response->setCharset('UTF-8');
$response->headers->set('Content-Type', 'text/plain');
Až jsme s odpovědí spokojeni, tak ji pošleme zavoláním metody
$response->send();
Pokud chceme mít jistotu, že vše v odpovědi je nastaveno správně, musíme před samotným odesláním zavolat
$response->prepare($request); $response->send();
Zatímco třída pro HTTP požadavek byla jen jedna, Pro HTTP odpověď nabízí komponenta HttpFoundation tříd několik. Pokud chceme provést přesměrování, použijeme
use Symfony\Component\HttpFoundation\RedirectResponse;
$response = new RedirectResponse('https://www.zdrojak.cz');
Pro poslání souboru se skvěle hodí
use Symfony\Component\HttpFoundation\BinaryFileResponse;
$response = new BinaryFileResponse('path/to/file.txt');
Tato třída automaticky nastaví HTTP hlavičky Range
, If-Range
, a X-Sendfile.
Pokud chceme změnit název souboru, pod kterým nám ho prohlížeč nabídne uložit, stačí zavolat metodu
use Symfony\Component\HttpFoundation\ResponseHeaderBag; $response->setContentDisposition( ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'filename.txt' );
A pro JSON zvolíme
use Symfony\Component\HttpFoundation\JsonResponse;
$response = new JsonResponse(['data' => 123]);
Zase o krok dále
V dnešním díle jsme si ukázali:
- jak funguje komunikace mezi prohlížečem a serverem,
- jak nainstalovat a začít používat HttpFoundation,
- jak místo několika superglobálních PHP polí používat jeden jediný objekt třídy
Request
, - jak vykreslovat stránky či vracet soubory a JSON data pomocí tříd
Response
, - ale hlavně, jak psát webové aplikace čistě pomocí Symfony komponenty HttpFoundation.
Kam jít dál?
Všechny možnosti komponenty HttpFoundation jsou krásně popsány v oficiální dokumentaci. Kapitola Symfony and HTTP Fundamentals podrobně vysvětluje propojení Symfony frameworku s HTTP protokolem.
Super praca Martin, diky