Petite bibliothèque PHP pour la manipulation des entrées de type.
Disons que vous avez une action qui répertorie certaines entités. Cela comprend la pagination, la commande ascendante ou descendante et le filtrage facultatif au moment de la création de l'entité. Cette action aura une sorte d'analyse d'entrée, qui peut ressembler à ceci:
public function index ()
{
$ page = $ this -> request -> query -> get ( ' page ' );
if ( $ page === null || ! is_integer ( $ page )) {
throw new Exception ( " Parameter page not found " );
}
$ order = $ this -> request -> query -> get ( ' order ' );
if ( $ order === null || ! in_array ( $ order , [ ' asc ' , ' desc ' ])) {
throw new Exception ( " Parameter order not found " );
}
// Optional parameter
$ createdAt = $ this -> query -> query -> get ( ' createdAt ' );
if ( is_string ( $ createdAt )) {
$ createdAt = new DateTime ( $ createdAt );
} else {
$ createdAt = null ;
}
}De toute évidence, ce code n'est pas très agréable à lire car il n'est pas très descriptif. C'est aussi assez verbeux pour ce qu'il fait. Et lorsque vous ne portez pas d'attention minutieuse, vous manquerez probablement un chèque nul ou un chèque de type.
Comparez maintenant le code ci-dessus à cette version:
public function index ()
{
$ page = $ this -> queryParameter ( ' page ' )-> int ()-> required ();
$ order = $ this -> queryParameter ( ' order ' )-> oneOf ([ ' asc ' , ' desc ' ])-> required ();
$ createdAt = $ this -> queryParameter ( ' createdAt ' )-> dateTime ()-> defaultsTo ( null );
}C'est ce que cette bibliothèque offre. Il vous permet d'exprimer " Cette action nécessite un paramètre de page de type int " ou " Cette action a un paramètre facultatif créé de type DateTime, et sera défini sur une valeur par défaut si elle est absente ".
Si vous souhaitez passer directement au code maintenant, vous pouvez simplement jouer avec les exemples.
cd /tmpgit clone [email protected]:mpscholten/request-parser.gitcd request-parsercomposer installcd examplesphp -S localhost:8080Il existe également plusieurs autres fichiers PHP dans le répertoire d'exemples. Pour vous salir les mains, je vous suggère de simplement modifier un peu les exemples.
Installer via le compositeur
composer require mpscholten/request-parser
symfony/http-foundation , cliquez ici.ServerRequestInterface , cliquez ici.Request (ou peut-être tout simplement vieux $_GET et amis), consultez cet exemple. L'exemple suivant suppose que vous utilisez la Request Symfony:
class MyController
{
use MPScholten RequestParser Symfony ControllerHelperTrait;
public function __construct ( Request $ request )
{
$ this -> initRequestParser ( $ request );
}
}Ensuite, vous pouvez utiliser la bibliothèque comme ceci:
class MyController
{
use MPScholten RequestParser Symfony ControllerHelperTrait;
public function __construct ( Request $ request )
{
$ this -> initRequestParser ( $ request );
}
public function myAction ()
{
$ someParameter = $ this -> queryParameter ( ' someParameter ' )-> string ()-> required ();
}
} Lorsque vous faites GET /MyController/myAction?someParameter=example , la variable $someParameter contiendra la chaîne "example" .
Vous vous demandez peut-être ce qui se passe lorsque nous laissons de côté la partie ?someParameter , comme GET /MyController/myAction . Dans ce cas, le $this->queryParameter('someParameter')->string()->required() lancera une NotFoundException . Cette exception peut être gérée par votre application pour afficher un message d'erreur.
Jetez un œil aux exemples.
L'exemple suivant suppose que vous utilisez le PSR7 ServerRequestInterface :
class MyController
{
use MPScholten RequestParser Psr7 ControllerHelperTrait;
public function __construct ( ServerRequestInterface $ request )
{
$ this -> initRequestParser ( $ request );
}
}Ensuite, vous pouvez utiliser la bibliothèque comme ceci:
class MyController
{
use MPScholten RequestParser Psr7 ControllerHelperTrait;
public function __construct ( ServerRequestInterface $ request )
{
$ this -> initRequestParser ( $ request );
}
public function myAction ()
{
$ someParameter = $ this -> queryParameter ( ' someParameter ' )-> string ()-> required ();
}
} Lorsque vous faites GET /MyController/myAction?someParameter=example , la variable $someParameter contiendra la chaîne "example" .
Vous vous demandez peut-être ce qui se passe lorsque nous laissons de côté la partie ?someParameter , comme GET /MyController/myAction . Dans ce cas, le $this->queryParameter('someParameter')->string()->required() lancera une NotFoundException . Cette exception peut être gérée par votre application pour afficher un message d'erreur.
Jetez un œil aux exemples.
Pour rendre le someParameter en option, nous pouvons simplement remplacer required() par defaultsTo($someDefaultValue) :
class MyController
{
use MPScholten RequestParser Symfony ControllerHelperTrait;
public function __construct ( Request $ request )
{
$ this -> initRequestParser ( $ request );
}
public function myAction ()
{
$ someParameter = $ this -> queryParameter ( ' someParameter ' )-> string ()-> defaultsTo ( ' no value given ' );
}
} Lorsque vous faites GET /MyController/myAction , la variable $someParameter contiendra désormais la chaîne "no value given" . Aucune exception ne sera lancée car nous avons spécifié une valeur par défaut.
En général, vous spécifiez d'abord le nom du paramètre, suivi du type, puis spécifiez si le paramètre est requis ou est facultatif avec une valeur par défaut.
Pour plus d'exemples, consultez les examples/ répertoire de ce référentiel. Il contient plusieurs exemples de course.
Souvent, nous avons besoin de plus que de simples cordes. RequestParser fournit également des méthodes pour d'autres types de données:
class DashboardController
{
public function show ()
{
$ dashboardId = $ this -> queryParameter ( ' id ' )-> int ()-> required ();
// GET /dashboard?name=Hello => $dashboardName == "Hello"
$ dashboardName = $ this -> queryParameter ( ' name ' )-> string ()-> required ();
// Get /dashboard?name= => $dashboardName == "default value"
$ dashboardName = $ this -> queryParameter ( ' name ' )-> string ()-> defaultsToIfEmpty ( " default value " );
// GET /dashboard?status=private => $dashboardStatus == "private"
// GET /dashboard?status=public => $dashboardStatus == "public"
// GET /dashboard?status=invalid => A NotFoundException will be thrown
$ dashboardStatus = $ this -> queryParameter ( ' status ' )-> oneOf ([ ' private ' , ' public ' ])-> required ();
// GET /dashboard?createdAt=01.01.2016 => $dateTime == new DateTime("01.01.2016")
// GET /dashboard?createdAt=invalid_date => A NotFoundException will be thrown
$ dateTime = $ this -> queryParameter ( ' createdAt ' )-> dateTime ()-> required ();
// GET /dashboard?config={"a":true} => $json == ['a' => true]
$ json = $ this -> queryParameter ( ' config ' )-> json ()-> required ();
// GET /dashboard?includeWidgets=true => $includeWidgets == true
// GET /dashboard?includeWidgets=false => $includeWidgets == false
// GET /dashboard?includeWidgets=0 => $includeWidgets == false
// GET /dashboard?includeWidgets=abcde => A NotFoundException will be thrown
$ includeWidgets = $ this -> queryParameter ( ' includeWidgets ' )-> boolean ()-> required ();
// GET /dashboard?includeWidgets=yes => $includeWidgets == true
// GET /dashboard?includeWidgets=no => $includeWidgets == false
$ includeWidgets = $ this -> queryParameter ( ' includeWidgets ' )-> yesNoBoolean ()-> required ();
// GET /image?scale=2.5 => $scale == 2.5
$ scale = $ this -> queryParameter ( ' scale ' )-> float ()-> required ();
}
} Tous ces types fournissent également une variante defaultsTo .
| Taper | Exemple de code | Exemple d'entrée |
|---|---|---|
| Chaîne | $this->queryParameter('name')->string()->required(); | 'John Doe' |
| Chaîne séparée par des virgules | $this->queryParameter('names')->commaSeparated()->string()->required(); | 'John Doe,John Oliver' |
| Entier | $this->queryParameter('id')->int()->required(); | '5' |
| Entier séparé des virgules | $this->queryParameter('groupIds')->commaSeparated()->int()->required(); | '5,6,7,8' |
| Flotter | $this->queryParameter('ratio')->float()->required(); | '0.98' |
| Chariot séparé des virgules | $this->queryParameter('precipitation')->commaSeparated()->float()->required(); | '0.98,1.24,5.21' |
| DateTime | $this->queryParameter('timestamp')->dateTime()->required(); | '2016-07-20' |
| DateTime séparée par des virgules | $this->queryParameter('eventTimes')->commaSeparated()->dateTime()->required(); | '2016-07-20 13:10:50,2016-07-21 12:01:07' |
| Booléen | $this->queryParameter('success')->boolean()->required(); | 'true' |
| Booléen séparé des virgules | $this->queryParameter('answers')->commaSeparated()->boolean()->required(); | '1,0,0,1' |
| Oui / Non Boolean | $this->queryParameter('success')->yesNoBoolean()->required(); | 'yes' |
| Séparation des virgules oui / non booléen | $this->queryParameter('answers')->commaSeparated()->yesNoBoolean()->required(); | 'y,n,n,y,n' |
| Json | $this->queryParameter('payload')->json()->required(); | '{"event":"click","timestamp":"2016-07-20 13:10:50"}' |
| JSON séparée par des virgules | $this->queryParameter('events')->commaSeparated()->json()->required(); | '{"event":"click","timestamp":"2016-07-20 13:10:50"},{"event":"add_to_basket","timestamp":"2016-07-20 13:11:01"}' |
$this->queryParameter($name) indique au contrôleur que nous voulons un paramètre de requête (tout après le "?" est appelé la chaîne de requête). C'est généralement ce que nous voulons lors de la gestion des demandes de GET
Lorsque nous avons affaire à une demande de poste, nous devons utiliser $this->bodyParameter($name) pour accéder aux champs de formulaire ou à la charge utile AJAX.
La bibliothèque vous permet d'utiliser une utilisation approfondie des fonctionnalités de complétion automatique de votre IDE. Par exemple, après avoir tapé $this->queryParameter('someParameter)-> Votre IDE vous offrira tous les types d'entrée possibles, par exemple string() ou int() . Après avoir choisi un type, par exemple string() , votre IDE offrira required() ou defaultsTo(defaultValue) pour spécifier le comportement lorsque le paramètre n'est pas défini.



La bibliothèque prend en charge l'analyse statique par votre IDE. Par exemple lorsqu'il a un paramètre comme $createdAt = $this->queryParameter('createdAt')->dateTime()->required(); , votre IDE saura que $createdAt est un objet DateTime . Cela vous permet de détecter les erreurs de type lors de l'édition et diminue également le coût de maintenance d'une action car les types améliorent la lisibilité.
La bibliothèque diminue également le risque de valeurs nulles inattendues car les paramètres ont toujours une valeur par défaut explicite ou sont nécessaires.
Lorsqu'un paramètre est requis mais non trouvé ou lorsque la validation échoue, la bibliothèque lancera une exception. Les exceptions par défaut sont MPScholtenRequestParserNotFoundException et MPScholtenRequestParserInvalidValueException . La façon suggérée de gérer les erreurs lancées par la bibliothèque est de les attraper à l'intérieur de votre contrôleur avant:
try {
$ controller -> $ action ();
} catch ( NotFoundException $ e ) {
echo $ e -> getMessage ();
} catch ( InvalidValueException $ e ) {
echo $ e -> getMessage ();
} class MyController
{
use MPScholten RequestParser Symfony ControllerHelperTrait;
public function __construct ( Request $ request )
{
$ exceptionFactory = new ExceptionFactory (CustomNotFoundException::class, CustomInvalidValueException::class));
$ config = new MPScholten RequestParser Config ();
$ config -> setExceptionFactory ( $ exceptionFactory );
$ this -> initRequestParser ( $ request , $ config );
}
} Si vous devez remplacer le message d'exception lancé par la bibliothèque une ou deux fois, vous pouvez le faire en faisant passer les messages d'exception comme premier et deuxième argument à ->required() :
class DashboardController
{
public function show ()
{
$ dashboardId = $ this -> queryParameter ( ' id ' )-> int ()-> required ( " The dashboard id has to be a valid number " , " No dashboard id given " );
}
}Si vous ne souhaitez pas spécifier un message d'exception personnalisé pour toutes vos actions, mais que vous ne souhaitez toujours pas utiliser les messages d'exception intégrés, vous pouvez fournir votre propre générateur de messages d'exception:
class FriendlyExceptionMessageFactory extends MPScholten RequestParser ExceptionMessageFactory
{
protected function createNotFoundMessage ( $ parameterName )
{
return " Looks like $ parameterName is missing :) " ;
}
protected function createInvalidValueMessage ( $ parameterName , $ parameterValue , $ expected )
{
return " Whoops :) $ parameterName seems to be invalid. We're looking for $ expected but you provided ' $ parameterValue ' " ;
}
}
class MyController
{
use MPScholten RequestParser Symfony ControllerHelperTrait;
public function __construct ( Request $ request )
{
$ config = new MPScholten RequestParser Config ();
$ config -> setExceptionMessageFactory ( new FriendlyExceptionMessageFactory ());
$ this -> initRequestParser ( $ request , $ config );
}
}Vérifiez cet exemple sur les exceptions personnalisées.
Absolument. Cette bibliothèque a été initialement développée au niveau et est largement utilisée en production depuis avril 2015. L'utiliser à grande échelle en production signifie qu'il y a une grande focalisation sur la compatibilité en arrière et ne pas casser les choses.
composer tests
composer tests-coverage
N'hésitez pas à envoyer des demandes de traction!