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

Zdroják » PHP » Symfony po krůčkách – Paralýza možností? OptionsResolver tě zachrání

Symfony po krůčkách – Paralýza možností? OptionsResolver tě zachrání

Články PHP

Abychom podpořili klidnou vánoční náladu, vybrali jsme pro dnešní díl jednu z nejjednodušších Symfony komponent – OptionsResolver. Co to je? `Array_replace` na steroidech. Oproti němu má navíc pár užitečných metod – ty se postarají o to, aby hodnoty byly validní, a zajistí i normalizaci.

Kdy se OptionsResolver hodí?

1.  Jestli jsi někdy navrhoval REST API, možná znáš:

<?php

$options = [
    'page' => isset($input['page']) ? $input['page'] : 1,
    'type' => isset($input['type']) ? $input['type'] : 'product'
];

2. Nebo jsi dělal CLI aplikaci, která má mnoho vstupních hodnot – jako např. PHP_CodeSniffer:

$ php phpcs [-nwlsaepvi] [-d key[=value]] [--colors] [--no-colors] [--report=<report>] [--report-file=<reportFile>] [--report-<report>=<reportFile>] [--report-width=<reportWidth>] [--generator=<generator>] [--tab-width=<tabWidth>] [--severity=<severity>]...

3. A nebo modul se složitějším nastavením – jako např. rozšíření pro Doctrine:

// config.yml / config.neon
doctrine:
    orm:
    database: …
    password: …
    port: …
       entity_manager:
          one:
             ...

Co mají tyto příklady společného?

Mají mnoho vstupních hodnot:

  • ty mohou nabývat různých stavů
  • potřebují validaci typu (např. řetězec, číslo…,) nebo vůči seznamu hodnot (např. buď „ano“ nebo „ne“)
  • vyžadují normalizaci, aby se s nimi dále pracovalo lépe (např. doplnění relativní cesty na absolutní)
  • někdy mají defaultní hodnoty, jindy ne

Takový jednoduchý validátor jistě zvládne napsat každý. Jestli jsi ale v situaci, kdy s kódem pracuje více lidí, hodí se zvolit nějaké ověřené řešení. To by mělo mít dokumentaci a určité normy.

V těchto situacích ti přijde vhod OptionsResolver.

Jak vypadá použití v praxi?

Použití v praxi najdeš u ApiGenu. Pokud ho neznáš, Je to CLI aplikace, která generuje API dokumentaci zdrojového kódu.

Jako vstup má až přes 20 možností různých typů, mezi nimi pole, text nebo bool.

Každá nevalidní hodnota vede k ukončení běhu aplikace. S tím nám OptionsResolver pomůže. Jak? Mrkni na třídu ConfigurationOptionsResolver.

Krátký příklad

Vrátíme se k úvodnímu příkladu s REST API:

$options = [
    'page' => isset($input['page']) ? $input['page'] : 1,
    'type' => isset($input['type']) ? $input['type'] : 'clothes';
];

Na něm si ukážeme 3 hlavní featury této komponenty:

  • nastavení defaultních hodnot
  • validaci
  • normalizaci

Nejdříve si komponentu nainstalujeme přes composer:

$ composer require symfony/options-resolver

Přidáme autoloader a vytvoříme novou instanci OptionsResolveru:

// index.php
require_once __DIR__.'/vendor/autoload.php';

// $input = …;

$optionsResolver = new Symfony\Component\OptionsResolver\OptionsResolver;

1. Nastavení defaultních hodnot

Výše uvedené použití isset() nahradí metoda setDefaults():

$optionsResolver->setDefaults([
    'page' => 1,
    'type' => 'clothes'
]);

$options = $optionsResolver->resolve($input);

Co to udělá se vstupy?

$input = [];
// $options: 'page' => 1, type' => 'clothes'

$input = ['page' => 2];
// $options: 'page' => 2, 'type' => 'clothes'

$input = ['missing’ => 5];
// Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException

Přesně tak, OptionsResolver nám ošetří hodnoty, které nejsou povolené. To nám pomůže k lepší bezpečnosti aplikace.

Pro tip: Jako defaultní hodnotu můžeš použít i callback.

$optionsResolver->setDefault('page', function (Options $options) {
    return ('clothes’ === $options['type']) ? 1 : 2;
});

Pro tip 2: A jestli chceš přidat možnost bez defaultní hodnoty, tak takhle:

$optionsResolver->setDefined('wrapper');

2. Validace

Někde nám chce někdo zadat data, o která zrovna nestojíme. Pojďme si je zvalidovat.

$optionsResolver->setAllowedTypes('page', 'int');

Můžeme přidat i více typů:

$optionsResolver->setAllowedTypes('page', ['int', 'float']);

Povolené hodnoty taxativně vyjmenovat:

$optionsResolver->setAllowedTypes('page', [1, 2, 3, 4, 5]);

Nebo stejné omezení jako výše, ale zapsané pomocí callbacku:

$optionsResolver->setAllowedTypes('page', function ($value) {
     return $value >= 1 && $value <= 5;
));

3. Normalizace

Co to znamená? Normalizace je jakákoliv úprava dat po tom, co byla zvalidována. V našem případě zajistíme, aby se při vyžádání větší než povolené stránky zobrazila 10. strana.

$optionsResolver->setNormalizer('page', function ($options, $value) {
    $maxPage = 10;
    if ($value > 10) {
        return $maxPage;
    }

    return $value;
});

A jsi zase o krok dál…

Dnes jsme si ukázali komponentu, která nám v chaosu mnoha možností pomůže udržet jasný směr.

Teď už víš, že OptionsResolver ti umožní:

  • nastavit defaultní hodnoty
  • validovat vstupy
  • normalizovat hodnoty, pokud potřebují ještě nějaké modifikace
  • a že se hodí při psaní složitější CLI aplikace, REST API nebo nějaké konfigurace

 

Chceš vědět víc?

Potřebuješ poznat OptionsResolver do hloubky? Mrkni na oficiální dokumentaci.

 

Příští pondělí si dáme vánoční volno a pak budeme v seriálu opět pokračovat.

Krásné Vánoce vám všem!

Komentáře

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

Tohle je dost dobrý. Určitě vyzkouším.

soundczeck

Díky za seriál o Symfony!

radoslavius

Při použítí FOSRestBundle lze použít přes anotace obdobnou funcionalitu param fetcher – http://symfony.com/doc/current/bundles/FOSRestBundle/param_fetcher_listener.html

Diskobolos

… jsi opustil Nette a dal prednost Symfony? Nerypu, jen me zajimaji fakticke argumenty. Diky za odpoved.

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.