IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Symfony PHP Discussion :

[6.x][Validator] Auto mapping ne fonctionne pas


Sujet :

Symfony PHP

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2023
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2023
    Messages : 16
    Par défaut [6.x][Validator] Auto mapping ne fonctionne pas
    Salut tout le monde,

    J'ai une entité Personne qui possède des attributs notamment $lastName et $firstName qui n'accepte pas les valeurs null.

    Du coup, j'aimerais tester le validator qui peut se baser sur les contraintes de l'entité pour faire des validations basique grâce au paramètre automapping. Voilà, le lien de la documentation qui en parle: https://symfony.com/doc/current/doct...dating-objects. D'ailleurs, je me base sur la doc pour faire mon test.

    Je paramètre donc cela dans config/packages/validator.yaml:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    framework:
        validation:
            email_validation_mode: html5
     
            # Enables validator auto-mapping support.
            # For instance, basic validation constraints will be inferred from Doctrine's metadata.
            #auto_mapping:
            #    App\Entity\: []
            auto_mapping:
                App\Entity\: []
     
    when@test:
        framework:
            validation:
                not_compromised_password: false
    Du coup, je met exactement la configuration indiquée dans le fichier de conf validator.yaml.

    Mon controller:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    <?php
     
    namespace App\Controller;
     
    use App\Entity\Personne;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Routing\Annotation\Route;
    use Symfony\Component\Validator\Validator\ValidatorInterface;
     
    class PersonneController extends AbstractController
    {
        #[Route('/personne', name: 'create_personne')]
        public function createPersonne(
            ValidatorInterface $validator
        ): Response 
        {
            $personne = new Personne();
            $personne->setFirstName(null);
            $personne->setLastName('Brochard');
            $personne->setHeight(2);
            $personne->setBio('Une petite bio');
     
            $errors = $validator->validate($personne);
            if (count($errors) > 0) {
                return new Response((string) $errors, 400);
            }
        }
    }
    Lorsque je me rend sur /personne, j'obtiens une erreur HTTP 500:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    App\Entity\Personne::setFirstName(): Argument #1 ($firstName) must be of type string, null given,
    au lieu de faire fonctionner le validator et avoir une erreur 400.

    Savez vous ce qu'il me manque pour faire fonctionner l'auto_mapping s'il vous plaît?

    Je vous remercie par avance,

  2. #2
    Membre émérite
    Homme Profil pro
    Autre
    Inscrit en
    Juillet 2021
    Messages
    435
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Juillet 2021
    Messages : 435
    Par défaut
    Bonjour,

    Ton setter Personne::setFirstName() autorise uniquement un argument de type string, pas la valeur null.
    Il s'agit donc d'un problème de typage, il faut soit typer ton argument avec "?string" pour autoriser la valeur null, soit ne pas affecter la valeur null si celle-ci n'est pas autorisée.

    Un exemple avec les deux cas possibles (get/setLastName autorisent la valeur null contrairement à get/setFirstName) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    <?php
     
    namespace App\Entity;
     
    use App\Repository\PersonneRepository;
    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Validator\Constraints as Assert;
     
    #[ORM\Entity(repositoryClass: PersonneRepository::class)]
    class Personne
    {
        #[ORM\Id]
        #[ORM\GeneratedValue]
        #[ORM\Column]
        private ?int $id = null;
     
        #[ORM\Column(length: 255)]
        private ?string $firstName = null;
     
        #[ORM\Column(length: 255, nullable: true)]
        private ?string $lastName = null;
     
        public function getId(): ?int
        {
            return $this->id;
        }
     
        public function getFirstName(): ?string
        {
            return $this->firstName;
        }
     
        public function setFirstName(string $firstName): static
        {
            $this->firstName = $firstName;
     
            return $this;
        }
     
        public function getLastName(): ?string
        {
            return $this->lastName;
        }
     
        public function setLastName(?string $lastName): static
        {
            $this->lastName = $lastName;
     
            return $this;
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <?php
     
    namespace App\Controller;
     
    use App\Entity\Personne;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Routing\Annotation\Route;
    use Symfony\Component\Validator\Validator\ValidatorInterface;
     
    class PersonneController extends AbstractController
    {
        #[Route('/personne', name: 'app_personne')]
        public function index(ValidatorInterface $validator): Response
        {
            $personne = new Personne();
            $personne->setFirstName(null); // 500: Argument #1 ($firstName) must be of type string
            $personne->setLastName(null); // pas d'erreur
     
            $errors = $validator->validate($personne);
            if (count($errors) > 0) {
                return new Response((string) $errors, 400);
            }
        }
    }

    Pour utiliser la validation, il faut ajouter des contraintes de validation à ton entité : https://symfony.com/doc/6.4/validation.html#constraints
    Un exemple avec les contraintes NotBlank et NotNull sur les propriété de l'entité Personnne (la doc utilise l'alias Assert) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <?php
     
    namespace App\Entity;
     
    use App\Repository\PersonneRepository;
    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Validator\Constraints as Assert;
     
    #[ORM\Entity(repositoryClass: PersonneRepository::class)]
    class Personne
    {
        #[ORM\Id]
        #[ORM\GeneratedValue]
        #[ORM\Column]
        private ?int $id = null;
     
        #[ORM\Column(length: 255)]
        #[Assert\NotBlank]
        private ?string $firstName = null;
     
        #[ORM\Column(length: 255, nullable: false)]
        #[Assert\NotNull]
        private ?string $lastName = null;
     
        // [...]
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <?php
     
    namespace App\Controller;
     
    use App\Entity\Personne;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Routing\Annotation\Route;
    use Symfony\Component\Validator\Validator\ValidatorInterface;
     
    class PersonneController extends AbstractController
    {
        #[Route('/personne', name: 'app_personne')]
        public function index(ValidatorInterface $validator): Response
        {
            $personne = new Personne();
            $personne->setFirstName(''); // 400: "This value should not be blank."
            $personne->setLastName(null); // 400: "This value should not be null."
     
            $errors = $validator->validate($personne);
            if (count($errors) > 0) {
                return new Response((string) $errors, 400);
            }
        }
    }

  3. #3
    Membre averti
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2023
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2023
    Messages : 16
    Par défaut
    Salut Pytet,

    Merci pour ta réponse qui m'a permis de finalement faire fonctionner l'auto_mapping dans Symfony.

    Je rappelle que l'auto_mapping, c'est le fait que le validateur effectue des validations en fonction de metadata sans les Assert. Ce que tu as mentionné Pytet pourra compléter la réponse. Donc je te remercie.

    Je corrigé ce qui n'allait pas en faisant en sorte déjà que les méthodes comme setFirstName ou setLastName acceptent les valeurs nulles avec le typage suivant en paramètre de la variable ?string comme tu me l'as conseillé.

    Exemple pour setLastName:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public function setLastName(?string $lastName): static
    {
       $this->lastName = $lastName;
     
       return $this;
    }
    Dans mon test, j'ai cette entité Personne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    <?php
     
    namespace App\Entity;
     
    use App\Repository\PersonneRepository;
    use Doctrine\DBAL\Types\Types;
    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Validator\Constraints as Assert;
     
    #[Assert\EnableAutoMapping]
    #[ORM\Entity(repositoryClass: PersonneRepository::class)]
    class Personne
    {
        #[ORM\Id]
        #[ORM\GeneratedValue]
        #[ORM\Column]
        private ?int $id = null;
     
        #[ORM\Column(length: 255)]
        private ?string $lastName = null;
     
        #[ORM\Column(length: 255)]
        private ?string $firstName = null;
     
        #[ORM\Column(nullable: true)]
        private ?float $height = null;
     
        #[ORM\Column(type: Types::TEXT)]
        private ?string $bio = null;
     
        #[ORM\Column(length: 255)]
        private ?string $hobby;
     
        public function getId(): ?int
        {
            return $this->id;
        }
     
        public function getLastName(): ?string
        {
            return $this->lastName;
        }
     
        public function setLastName(?string $lastName): static
        {
            $this->lastName = $lastName;
     
            return $this;
        }
     
        public function getFirstName(): ?string
        {
            return $this->firstName;
        }
     
        public function setFirstName(?string $firstName): static
        {
            $this->firstName = $firstName;
     
            return $this;
        }
     
        public function getHeight(): ?float
        {
            return $this->height;
        }
     
        public function setHeight(?float $height): static
        {
            $this->height = $height;
     
            return $this;
        }
     
        public function getBio(): ?string
        {
            return $this->bio;
        }
     
        public function setBio(string $bio): static
        {
            $this->bio = $bio;
     
            return $this;
        }
     
        public function getHobby(): ?string
        {
            return $this->hobby;
        }
     
        public function setHobby(string $hobby): static
        {
            $this->hobby = $hobby;
     
            return $this;
        }
    }
    Je rappelle le paramétrage du validator pour l'auto_mapping dans /config/packages/validator.yaml:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    framework:
        validation:
            email_validation_mode: html5
            auto_mapping:
                App\Entity\: []
    1) Mon premier test avec le controlleur suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class PersonneController extends AbstractController
    {
        #[Route('/personne', name: 'create_personne')]
        public function createPersonne(ValidatorInterface $validator) 
        {
            $personne = new Personne();
            $personne->setFirstName(null);
            $personne->setLastname(null);
            $personne->setHeight(2);
            $personne->setBio('Une petite bio');
     
            $errors = $validator->validate($personne);
            if (count($errors) > 0) {
                return new Response((string) $errors, 400);
            }
        }
    }
    Lorsque je lance la route /personne, j'essaie de setter le firstName et le lastName à null et je met des valeurs pour height et bio. J'obtiens du coup le bon retour du validator:

    Object(App\Entity\Personne).lastName: This value should not be null. (code ad32d13f-c3d4-423b-909a-857b961eb720)

    Object(App\Entity\Personne).firstName: This value should not be null. (code ad32d13f-c3d4-423b-909a-857b961eb720)

    Object(App\Entity\Personne).hobby: This value should not be null. (code ad32d13f-c3d4-423b-909a-857b961eb720)
    Ainsi, on a bien une validation directe en se basant sur les metadata (comme le nullable:false implicite). D'ailleurs, pour les valeurs que je n'ai pas setté comme firstName ou hobby, j'ai aussi un message du validator, c'est par ce que si on ne sette pas les autres attributs ils sont par défaut setté à null comme indiqué dans le code de l'entité.

    2) J'ai du coup fait un deuxième test avec ce controlleur pour bien confirmer ce que j'ai constaté:

    Je set que le firstName à null et je ne sette pas le lastName ni le height et le bio qui avaient respectivement les valeurs 2 et "Une petite bio" et je trouve quelque chose d'intéressant:

    Object(App\Entity\Personne).lastName: This value should not be null. (code ad32d13f-c3d4-423b-909a-857b961eb720)

    Object(App\Entity\Personne).firstName: This value should not be null. (code ad32d13f-c3d4-423b-909a-857b961eb720)

    Object(App\Entity\Personne).bio: This value should not be null. (code ad32d13f-c3d4-423b-909a-857b961eb720)

    Object(App\Entity\Personne).hobby: This value should not be null. (code ad32d13f-c3d4-423b-909a-857b961eb720)
    Si je ne sette pas lastName c'est comme si on lui affectais la valeur null comme il est initialisé par défaut dans l'entité. Height est nullable, il n'est du coup pas pris en compte. Enfin, bio et hobby sont pris en compte par le validator comme ils sont nullable et initialisés dans l'entité à 0.

    Du coup, l'auto_mapping fonctionne maintenant.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Web Service][API Google Maps] Ne fonctionne pas en ligne
    Par PRACH dans le forum Bibliothèques et frameworks
    Réponses: 4
    Dernier message: 07/12/2009, 10h30
  2. Auto-connect ne fonctionne pas
    Par guyguy333 dans le forum Débuter
    Réponses: 17
    Dernier message: 06/09/2008, 21h41
  3. Excel, listes de validation auto-completion
    Par Carmiel dans le forum Excel
    Réponses: 6
    Dernier message: 30/08/2008, 18h53
  4. Validation formulaire qui ne fonctionne pas
    Par dom59111 dans le forum Langage
    Réponses: 6
    Dernier message: 25/10/2007, 10h18
  5. [Validator] depends validwhen ne fonctionne pas !
    Par BBG2.0 dans le forum Struts 1
    Réponses: 13
    Dernier message: 14/09/2007, 11h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo