2
votes

I'm following a symfony tutorial on form validation.

Here $title should be valued as unique entitity and it works, but the same error message shows up on $content field.

Aside, I'm tryng also to get the content to be validated form "Antiflood" Constraint and its "Validator". (when I comment the title validation and try at least to make the Antiflood works...) I realize it works (the form doesn't validate) but I got no error message...

Error with title validation (double message) enter image description here

Error with constraintValidator (works but no message) enter image description here My Constraint

<?php
// src/OC/PlatformBundle/Validator/Antiflood.php

namespace OC\PlatformBundle\Validator;

use Symfony\Component\Validator\Constraint;

    /**
     * @Annotation
     */
    class Antiflood extends Constraint
    {
      public $message = "Vous avez déjà posté un message il y a moins de 15 secondes, merci d'attendre un peu.";
    }

My validator

<?php
// src/OC/PlatformBundle/Validator/AntifloodValidator.php

namespace OC\PlatformBundle\Validator;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class AntifloodValidator extends ConstraintValidator
{
  public function validate($value, Constraint $constraint)
  {
    // Pour l'instant, on considère comme flood tout message de moins de 3 caractères
    if (strlen($value) < 3) {
      // C'est cette ligne qui déclenche l'erreur pour le formulaire, avec en argument le message de la contrainte
      $this->context->addViolation($constraint->message);
    }
  }
}

My Adver.php

namespace OC\PlatformBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\PreUpdate;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use OC\PlatformBundle\Validator\Antiflood;

/**
 * Advert
 * @ORM\Entity()
 * @ORM\Table(name="advert")
 * @ORM\Entity(repositoryClass="OC\PlatformBundle\Entity\AdvertRepository")
 * @ORM\HasLifecycleCallbacks()
 * @UniqueEntity(fields="title", message="Une annonce existe déjà avec ce titre.")
 */
class Advert {

    /**
     * @ORM\OneToMany(targetEntity="OC\PlatformBundle\Entity\Application", mappedBy="advert")
     */
    private $applications;

    /**
     * @ORM\ManyToMany(targetEntity="OC\PlatformBundle\Entity\Category", cascade={"persist"})
     */
    private $categories;

    /**
     * @ORM\OneToOne(targetEntity="OC\PlatformBundle\Entity\Image", cascade={"persist", "remove"})
     * @Assert\Valid()
     */
    private $image;

    /**
     *
     * @var boolean @ORM\Column(name="published", type="boolean")
     */
    private $published = true;

    /**
     *
     * @var integer @ORM\Column(name="id", type="integer")
     *      @ORM\Id
     *      @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     *
     * @var \DateTime @ORM\Column(name="date", type="datetime")
     *      @Assert\DateTime()
     */
    private $date;

    /**
     *
     * @var string @ORM\Column(name="title", type="string", length=255, unique=true)
     *      @Assert\Length(min=10)
     */
    private $title;

    /**
     *
     * @var string @ORM\Column(name="author", type="string", length=255)
     *      @Assert\Length(min=2)
     */
    private $author;

    /**
     *
     * @var string @ORM\Column(name="content", type="text")
     *      @Assert\NotBlank()
     *      @Antiflood()
     */
    private $content;

    /**
     * @ORM\Column(name="updated_at", type="datetime", nullable=true)
     */
    private $updatedAt;

    /**
     * @ORM\Column(name="nb_applications", type="integer", nullable=true)
     */
    private $nbApplications;

    /**
     * @Gedmo\Slug(fields={"title"})
     * @ORM\Column(length=128, unique=true)
     */
    private $slug;

    /**
     * @ORM\ManyToMany(targetEntity="OC\PlatformBundle\Entity\AdvertSkill", mappedBy="adverts")
     * @ORM\JoinColumn(nullable=false)
     */
    private $advertSkills;
    public function __construct() {
        // Par défaut, la date de l'annonce est la date d'aujourd'hui
        $this-&gt;date = new \Datetime ();
        $this-&gt;categories = new ArrayCollection ();
        $this-&gt;applications = new ArrayCollection ();
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId() {
        return $this-&gt;id;
    }
    public function setDate($date) {
        $this-&gt;date = $date;
        return $this;
    }

    /**
     * Set date
     *
     * @param \DateTime $date           
     * @return Advert @ORM\PrePersist()
     */
    public function setDateAuto() {
        $this-&gt;date = new \Datetime ();
        return $this;
    }

    /**
     * Get date
     *
     * @return \DateTime
     */
    public function getDate() {
        return $this-&gt;date;
    }

    /**
     * Set title
     *
     * @param string $title         
     * @return Advert
     */
    public function setTitle($title) {
        $this-&gt;title = $title;

        return $this;
    }

    /**
     * Get title
     *
     * @return string
     */
    public function getTitle() {
        return $this-&gt;title;
    }

    /**
     * Set author
     *
     * @param string $author            
     * @return Advert
     */
    public function setAuthor($author) {
        $this-&gt;author = $author;

        return $this;
    }

    /**
     * Get author
     *
     * @return string
     */
    public function getAuthor() {
        return $this-&gt;author;
    }

    /**
     * Set content
     *
     * @param string $content           
     * @return Advert
     */
    public function setContent($content) {
        $this-&gt;content = $content;

        return $this;
    }

    /**
     * Get content
     *
     * @return string
     */
    public function getContent() {
        return $this-&gt;content;
    }

    /**
     * Set published
     *
     * @param boolean $published            
     * @return Advert
     */
    public function setPublished($published) {
        $this-&gt;published = $published;

        return $this;
    }

    /**
     * Get published
     *
     * @return boolean
     */
    public function getPublished() {
        return $this-&gt;published;
    }

    /**
     * Set image
     *
     * @param \OC\PlatformBundle\Entity\Image $image            
     * @return Advert
     */
    public function setImage(\OC\PlatformBundle\Entity\Image $image = null) {
        $this-&gt;image = $image;

        return $this;
    }

    /**
     * Get image
     *
     * @return \OC\PlatformBundle\Entity\Image
     */
    public function getImage(Image $image = null) {
        return $this-&gt;image;
    }

    /**
     * Add categories
     *
     * @param \OC\PlatformBundle\Entity\Category $categories            
     * @return Advert
     */
    public function addCategory(Category $categories) {
        $this-&gt;categories [] = $categories;

        return $this;
    }

    /**
     * Remove categories
     *
     * @param \OC\PlatformBundle\Entity\Category $categories            
     */
    public function removeCategory(Category $categories) {
        $this-&gt;categories-&gt;removeElement ( $categories );
    }

    /**
     * Get categories
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getCategories() {
        return $this-&gt;categories;
    }

    /**
     * Add applications
     *
     * @param \OC\PlatformBundle\Entity\Application $applications           
     * @return Advert
     */
    public function addApplication(\OC\PlatformBundle\Entity\Application $applications) {
        $this-&gt;applications [] = $applications;
        $applications-&gt;setAdvert ( $this ); // /!\ Retenez : on modifie le setter d'un côté, et on utilise ensuite ce setter-là
        return $this;
    }

    /**
     * Remove applications
     *
     * @param \OC\PlatformBundle\Entity\Application $applications           
     */
    public function removeApplication(\OC\PlatformBundle\Entity\Application $applications) {
        $this-&gt;applications-&gt;removeElement ( $applications );
    }

    /**
     * Get applications
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getApplications() {
        return $this-&gt;applications;
    }
    public function listAction() {
        $listAdverts = $this-&gt;getDoctrine ()-&gt;getManager ()-&gt;getRepository ( 'OCPlatformBundle:Advert' )-&gt;getAdvertWithApplications ();

        foreach ( $listAdverts as $advert ) {
            // Ne déclenche pas de requête : les candidatures sont déjà chargées !
            // Vous pourriez faire une boucle dessus pour les afficher toutes
            $advert-&gt;getApplications ();
        }

        // …
    }

    /**
     * Set updatedAt
     *
     * @param \DateTime $updatedAt          
     * @return Advert
     */
    public function setUpdatedAt($updatedAt) {
        $this-&gt;updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get updatedAt
     *
     * @return \DateTime
     */
    public function getUpdatedAt() {
        return $this-&gt;updatedAt;
    }

    /**
     * @ORM\PreUpdate
     */
    public function updateDate() {
        $this-&gt;setUpdatedAt ( new \DateTime () );
    }
    public function increaseApplication() {
        $this-&gt;nbApplications ++;
    }
    public function decreaseApplication() {
        $this-&gt;nbApplications --;
    }

    /**
     * Set nbApplications
     *
     * @param integer $nbApplications           
     * @return Advert
     */
    public function setNbApplications($nbApplications) {
        $this-&gt;nbApplications = $nbApplications;

        return $this;
    }

    /**
     * Get nbApplications
     *
     * @return integer
     */
    public function getNbApplications() {
        return $this-&gt;nbApplications;
    }

    /**
     * Set slug
     *
     * @param string $slug          
     * @return Advert
     */
    public function setSlug($slug) {
        $this-&gt;slug = $slug;

        return $this;
    }

    /**
     * Get slug
     *
     * @return string
     */
    public function getSlug() {
        return $this-&gt;slug;
    }

    // /**
    // * @Assert\True(message="Ce champs doit être rempli")
    // */
    // public function isTitle()
    // {
    // return false;
    // }

    /**
     * @Assert\Callback
     */
    public function isContentValid(ExecutionContextInterface $context) {

        // // MOT INDESIRABLES
        // $forbiddenWords = array('échec', 'abandon');

        // // On vérifie que le contenu ne contient pas l'un des mots
        // if (preg_match('#'.implode('|', $forbiddenWords).'#', $this-&gt;getContent())) {
        // // La règle est violée, on définit l'erreur
        // // $context
        // // -&gt;buildViolation('Contenu invalide car il contient un mot interdit.') // message
        // // -&gt;atPath('content') // attribut de l'objet qui est violé
        // // -&gt;addViolation() // ceci déclenche l'erreur, ne l'oubliez pas
        // // ;
        // $context-&gt;addViolation("Contenu invalide"); //!!!CORRECTE!!!
        // }
    }
}



{# src/OC/PlatformBundle/Resources/views/Advert/form.html.twig #}

<h3>Formulaire d'annonce</h3>

<div class="well">
  {{ form_start(form, {'attr': {'class': 'form-horizontal'}}) }}

    {# Les erreurs générales du formulaire. #}
    {{ form_errors(form) }}

    <div class="form-group">
      {# Génération du label. #}
      {{ form_label(form.title, "Titre de l'annonce", {'label_attr': {'class': 'col-sm-3 control-label'}}) }}

      {# Affichage des erreurs pour ce champ précis. #}
      {{ form_errors(form.title) }}

      <div class="col-sm-4">
        {# Génération de l'input. #}
        {{ form_widget(form.title, {'attr': {'class': 'form-control'}}) }}
      </div>
    </div>

    {# Idem pour un autre champ. #}
    <div class="form-group">
      {{ form_label(form.content, "Contenu de l'annonce", {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
      {{ form_errors(form.title) }}
      <div class="col-sm-4">
        {{ form_widget(form.content, {'attr': {'class': 'form-control'}}) }}
      </div>
    </div>

  {# Génération du label + error + widget pour un champ #}
  {% if form.date is defined %}
  <div class="form-group">
      {{ form_label(form.date, "Date de sousmission", {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
      {{ form_errors(form.date) }}
          <div class="col-sm-4">
            {{ form_widget(form.date) }}
          </div>
  </div>
{% endif %}
  <div class="form-group">
      {{ form_label(form.author, "Auteur", {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
      {{ form_errors(form.author) }}
          <div class="col-sm-4">
            {{ form_widget(form.author) }}
          </div>
  </div>
  {% if form.published is defined %}
  <div class="form-group">
      {{ form_label(form.published, "Published", {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
      {{ form_errors(form.published) }}
          <div class="col-sm-4">
            {{ form_widget(form.published) }}
          </div>
  </div>
  {% endif %}
  {% if advert.image is defined %}
  <img 
  src="{{ asset(advert.image.webPath) }}"
  alt="{{ advert.image.alt }}"
    />
    {% endif %}
  <div class="form-group">
    {{ form_label(form.save, "", {'label_attr': {'class': 'col-sm-3 control-label'}}) }}
      <div class="col-sm-4">
        {# Pour le bouton, pas de label ni d'erreur, on affiche juste le widget #}
        {{ form_widget(form.save, {'attr': {'class': 'btn btn-primary'}}) }}
      </div>
  </div>

  {# Génération automatique des champs pas encore écrits.
     Dans cet exemple, ce serait le champ CSRF (géré automatiquement par Symfony !)
     et tous les champs cachés (type « hidden »). #}
  {{ form_rest(form) }}

  {# Fermeture de la balise <form> du formulaire HTML #}
  {{ form_end(form) }}
</div>
1
What does you template look like ?paulgv
Got it! I had {{ form_errors(form.title) }} instead of {{ form_errors(form.content) }}!! Thanks for putting me on the way ;)Michele

1 Answers

0
votes

Got it! I had {{ form_errors(form.title) }} instead of {{ form_errors(form.content) }} in the twig template :S