Comment avoir un paramètre d’URL booléen avec le routeur Symfony ?
Je vois régulièrement cette question être posée sur le Slack communautaire de Symfony : Comment puis-je récupérer un paramètre d’URL directement en booléen avec le routeur Symfony ?
Je vais vous présenter une approche simple et pratique que je mets souvent en œuvre afin de répondre à cette question.
Déclarer explicitement le paramètre d'URL et convertir manuellement
L’approche la plus naïve à cette problématique est de passer la valeur 0
/1
ou false
/true
dans l’URL et de convertir
ensuite.
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
final class InvitationController extends AbstractController
{
#[Route(
path: '/invitation/{invitationId}/{isAccepted}',
name: 'api_invitation_change_status',
methods:['POST'],
requirements: ['isAccepted' => '0|1|true|false']
)]
public function __invoke(int $invitationId, string $isAccepted): Response
{
$isAccepted = filter_var($isAccepted, \FILTER_VALIDATE_BOOLEAN);
// ...
}
}
Cependant, cette approche nécessite de convertir le paramètre reçu en booléen ou, à défaut, de comparer la valeur
0
/1
ou false
/true
pour connaître l’action choisie.
Alternativement, on peut choisir de passer des verbes d’actions au lieu de 0
/1
pour se rapprocher des termes
métiers et donc gagner en clarté.
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
final class InvitationController extends AbstractController
{
#[Route(
path: '/invitation/{invitationId}/{action}',
name: 'api_invitation_change_status',
methods:['POST'],
requirements: ['action' => 'accept|decline']
)]
public function __invoke(int $invitationId, string $action): Response
{
$isAccepted = $action === 'accept' ? true : false;
// ...
}
}
Comme la méthode précédente, on doit effectuer une conversion supplémentaire afin de pouvoir déterminer le booléen.
Déclarer implicitement le paramètre d'URL
L’approche que je suggère est d’utiliser la notion d’Extra Parameters. On peut définir notre booléen sans avoir à le déclarer explicitement dans la configuration de la route.
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
final class InvitationController extends AbstractController
{
#[Route(
path: '/invitation/{invitationId}/accept',
name: 'api_invitation_accept',
methods:['POST'],
defaults: ['isAccepted' => true]
)]
#[Route(
path: '/invitation/{invitationId}/decline',
name: 'api_invitation_decline',
methods:['POST'],
defaults: ['isAccepted' => false]
)]
public function __invoke(int $invitationId, bool $isAccepted): Response
{
// ...
}
}
Cette approche a plusieurs avantages :
Les URL sont plus explicites.
Au lieu de passer une valeur
0
/1
oufalse
/true
dans l’URL ou de passer la valeur dans le corps de la requête, on utilise des termes métiers sans avoir à convertir la valeur.Les noms de routes sont explicites.
Ils peuvent être facilement référencée dans l’application, par exemple sur les boutons pour refuser/accepter l’invitation.
Néanmoins, la déclaration de Route
est plus verbeuse. On doit en déclarer 2 au lieu d'une seule et donc dupliquer les
paramètres.
Route Groups
pour limiter la duplication.On pourrait décliner cette approche pour gérer l’équivalent d’une énumération. Cependant, avec la validation des paramètres, cette astuce est moins intéressante surtout si le nombre de valeurs possibles est important.