Symfony po krůčkách – Validator (1)

V dnešním díle se podíváme na zoubek Symfony komponentě Validator. Tato komponenta slouží pro validaci dat – ověření toho, že hodnoty našich proměnných jsou správného typu, spadají do daného rozsahu hodnot nebo splňují jiná pravidla, která si nadefinujeme.
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
Aby nebyl článek příliš dlouhý, díl o komponentě Validator rozdělíme na dvě části. Dnes si v článku ukážeme, jak validovat skalární hodnoty, pole a jak zajistit překlady chybových zpráv. V příští části se podíváme na validaci objektů a skupiny validačních pravidel.
Zdrojový kód všech příkladů uvedených v tomto článku najdete v repozitáři na GitHubu
Jak začít s komponentou Validator
Komponentu Validator nainstalujeme pomocí nástroje Composer:
composer require symfony/validator
Nyní ji můžeme použít ve svém scriptu. Začněme jednoduchou validací, kdy ověříme, jestli uvedená hodnota není prázdná.
require_once __DIR__ . '/vendor/autoload.php';
use Symfony\Component\Validator\ValidatorBuilder;
use Symfony\Component\Validator\Constraints\NotBlank;
$builder = new ValidatorBuilder();
$validator = $builder->getValidator();
$violations = $validator->validate('', new NotBlank());
echo (string) $violations;
A to je celé. Po spuštění skriptu bychom měli vidět výpis s oznámením “This value should not be blank.”
Asi jste si všimli, že náš validátor jsme vytvořili pomocí objektu třídy VaidatorBuilder
. Je to z toho důvodu, že třída Validator
závisí na dalších třídách a vytvoření její instance není při prvním setkání s ní úplně triviální. ValidatorBuilder
nám instanci validátoru vytvoří s výchozím nastavením bez jakýchkoli problémů a my tak můžeme náš nový validátor okamžitě s radostí používat.
Metoda validate
Stěžejní částí příkladu je volání metody validate()
. Tato metoda očekává 3 argumenty, z toho pouze 1. je povinný. Ten představuje hodnotu, kterou chceme validovat. Může to být objekt, pole nebo skalární hodnota. V našem případě předáváme jednoduchou hodnotu, a to prázdný řetězec.
Jako druhý argument očekává metoda validační pravidlo, což je objekt typu Constraint
, proti kterému chceme hodnotu validovat. Můžeme předat i pole více pravidel, čímž validátoru řekneme, že chceme, aby hodnota splňovala všechna uvedená pravidla. V našem případě předáváme pouze pravidlo NotBlank
, které ověřuje, jestli hodnota není prázdná.
Zamysleme se nyní nad úkolem, kdy bychom chtěli ověřit, jestli je hodnota IP adresa. Pomocí validátoru je ověření snadné. V první řadě musíme zkontrolovat, jestli hodnota není prázdná, a za druhé, jestli se skutečně jedná o IP adresu. Podívejte se na následující ukázku:
// result: This value should not be blank.
echo (string) $validator->validate('', [new NotBlank(), new Ip()]);
// result: This is not a valid IP address.
echo (string) $validator->validate('22.gg.54.00', [new NotBlank(), new Ip()]);
// result: No violations
echo (string) $validator->validate('192.168.54.1', [new NotBlank(), new Ip()]);
Třetí argument je tzv. skupina. Ta nám určuje, jaká skupina validačních pravidel se má pro právě spouštěnou validaci použít. U každého validačního pravidla totiž můžeme zadat skupinu, do které patří, a jednoduše tak pravidla seskupovat. Více se k tomuto tématu dostaneme v příštím díle u validování objektů, kde definování skupin dává asi největší smysl.
Výsledkem volání metody validate()
je seznam všech nalezených chyb proti námi uvedeným pravidlům. Tyto chyby jsou typu ConstraintViolation
a obsahují informace o pravidle, které nebylo splněno, chybovou hlášku a několik dalších údajů.
Je to e-mail nebo IBAN?
Velkou výhodou komponenty Validator je její arzenál validačních pravidel, které v základu programátorům nabízí. V příkladu jsme použili validační pravidlo NotBlank a Ip. Je jich ale mnohem více. Jako příklad můžeme uvést e-mail, Url, Regex, Country, Iban, Callback, a další. Jejich kompletní seznam i s popisem konfigurace najdete v dokumentaci
Validace polí
Validace hodnoty je fajn. Často ale potřebujeme validovat hodnoty celých datových struktur. I na to Validator myslí. Pojďme se podívat na trochu zajímavější příklad validace asociativního pole hodnot. Takové pole můžeme například dostat z formuláře zaslaného HTTP požadavkem.
require_once __DIR__ . '/vendor/autoload.php';
use Symfony\Component\Validator\ValidatorBuilder;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Validator\Constraints\Collection;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\Type;
use Symfony\Component\Validator\Constraints\Range;
use Symfony\Component\Validator\Constraints\CardScheme;
$inputData = [
'name' => 'Jan',
'age' => 20,
'card' => '5111111111111111',
'email' => 'name@provider.com',
];
$violations = $validator->validate($inputData, new Collection([
'name' => [
new NotBlank(),
],
'age' => [
new NotBlank(),
new Type([
'type'=>'integer'
]),
new Range([
'min' => 18,
'max' => 80,
'minMessage' => "You must be at least {{ limit }} years old to enter.",
'maxMessage' => "You are too old. Entering is not safe for you. It Is only for persons younger than {{ limit }}",
]),
],
'card' => [
new NotBlank(),
new CardScheme([
'schemes' => ['MASTERCARD', 'VISA'],
]),
],
'email' => [
new NotBlank(),
new Email(),
],
]));
echo (string) $violations;
Vidíme, že princip validace je stejný. Opět voláme metodu validate()
. Nyní ovšem do této metody místo skalární hodnoty předáváme celé pole a jako validační pravidlo používáme objekt typu Collection
, díky kterému můžeme nadefinovat validační pravidla pro jednotlivé prvky pole. Všimněte si, že při vytváření validačních pravidel můžete do jejich konstruktoru předat pole s nastavením, čímž si každé pravidlo můžete přizpůsobit svým potřebám.
Vezměme si například validační pravidlo Length
. Tomu jsme nastavili hodnotu ‘min’ a ‘minMessage’. Tímto jsme řekli, že požadujeme, aby hodnota ‘note’ byla delší než 20 znaků a pokud to tak nebude, chceme o tom uživatele informovat zprávou „Your note must have at least 20 characters“, kde {{ limit }} se nahradil hodnotou uvedenou pod klíčem ‘min’.
Překlady chybových zpráv
Některé z vás by mohlo zajímat, jak se řeší překlady chybových zpráv. Zvídavější si už možná všimli, že při instalaci komponenty Validator se do složky vendor nainstalovala i komponenta Translator, na níž Validator závisí. Ve výchozím stavu používá Validator pro překlady objekt typu IdentityTranslator, který přímo nic nepřekládá, pouze ve zprávách nahrazuje případné zástupné parametry.
Pokud chcete, aby Validator používal váš vlastní Translator, vytvořte si jej podle postupu, jak jste se to naučili v předchozím díle seriálu, a předejte ho do objektu typu ValidatorBuilder
. Bude to vypadat nějak takto:
require_once __DIR__ . '/vendor/autoload.php';
use Symfony\Component\Validator\ValidatorBuilder;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Validator\Constraints\NotBlank;
// translator
$translator = new Translator('cs_CZ');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', [
'person.name.not_blank' => 'Hodnota nesmi byt prazdna!',
], 'cs_CZ');
$translator->addResource('array', [
'person.name.not_blank' => 'Value should not be blank!',
], 'en_EN');
// validator
$builder = new ValidatorBuilder();
$builder->setTranslator($translator);
$validator = $builder->getValidator();
// validation rule
$notBlank = new NotBlank([
'message' => 'person.name.not_blank'
])
// validation and result in czech
echo (string) $validator->validate('', $notBlank);
// validation and result in english
$translator->setLocale("en_EN");
echo (string) $validator->validate('', $notBlank);
V ukázce si nejdříve vytvoříme translator a načteme překlady. Překlady definujeme pomocí zástupného klíče. Pro přehlednost definujeme pouze jeden klíč ‚person.name.not_blank‘. Je dobré vědět, že každé validační pravidlo z komponenty Validator nám umožňuje nastavit si vlastní zprávu, která se uživateli zobrazí v případě chyby. Zpráva se validačnímu pravidlu nastavuje přes klíč ‚message‘. My v ukázce u pravidla NotBlank místo konkrétní zprávy použijeme právě zástupný klíč z definice překladů.
Zase o krok dál
V dnešním díle jsme si ukázali:
- jak nainstalovat a začít používat Validator
- jak validovat samostatné skalární hodnoty
- jak validovat složitější datové struktury jako pole
- jak lokalizovat chybové hlášky
Kam jít dál?
Seznam validačních pravidel a jejich možnosti konfigurace najdete na stránkách Symfony v sekci referencí.
Při rozšiřování Validátoru o vlastní validační pravidla se můžete inspirovat v CookBooku.
Začínáš se Symfony a chceš se rychle posunout dál? Přijď si popovídat na některé z našich setkání v Praze, Brně nebo Ostravě, také se můžeš zúčastnit našeho školení.
Aj ked to viac menej poznam, pekne vysvetlene, diky ;)
Díky, těšte se na další díl :)
Thank you very much for publishing this article! I’m reading the entire series (with Google Translate help) and I love it. As a very minor issue, I’d like to say that some elements are lacking the „“ tag to differentiate them from the regular text.
Anyway, thank you and keep up with the good work.
Thank you Javier. We are glad that you are watching us :) We all like Symfony framework, it helps us a lot with our projects so we want to spread our experience further.
And yes, you are right about that issue. I’ll try to improve it in next part of the series. Thanks for reporting.