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)
Error with constraintValidator (works but no message) 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->date = new \Datetime ();
$this->categories = new ArrayCollection ();
$this->applications = new ArrayCollection ();
}
/**
* Get id
*
* @return integer
*/
public function getId() {
return $this->id;
}
public function setDate($date) {
$this->date = $date;
return $this;
}
/**
* Set date
*
* @param \DateTime $date
* @return Advert @ORM\PrePersist()
*/
public function setDateAuto() {
$this->date = new \Datetime ();
return $this;
}
/**
* Get date
*
* @return \DateTime
*/
public function getDate() {
return $this->date;
}
/**
* Set title
*
* @param string $title
* @return Advert
*/
public function setTitle($title) {
$this->title = $title;
return $this;
}
/**
* Get title
*
* @return string
*/
public function getTitle() {
return $this->title;
}
/**
* Set author
*
* @param string $author
* @return Advert
*/
public function setAuthor($author) {
$this->author = $author;
return $this;
}
/**
* Get author
*
* @return string
*/
public function getAuthor() {
return $this->author;
}
/**
* Set content
*
* @param string $content
* @return Advert
*/
public function setContent($content) {
$this->content = $content;
return $this;
}
/**
* Get content
*
* @return string
*/
public function getContent() {
return $this->content;
}
/**
* Set published
*
* @param boolean $published
* @return Advert
*/
public function setPublished($published) {
$this->published = $published;
return $this;
}
/**
* Get published
*
* @return boolean
*/
public function getPublished() {
return $this->published;
}
/**
* Set image
*
* @param \OC\PlatformBundle\Entity\Image $image
* @return Advert
*/
public function setImage(\OC\PlatformBundle\Entity\Image $image = null) {
$this->image = $image;
return $this;
}
/**
* Get image
*
* @return \OC\PlatformBundle\Entity\Image
*/
public function getImage(Image $image = null) {
return $this->image;
}
/**
* Add categories
*
* @param \OC\PlatformBundle\Entity\Category $categories
* @return Advert
*/
public function addCategory(Category $categories) {
$this->categories [] = $categories;
return $this;
}
/**
* Remove categories
*
* @param \OC\PlatformBundle\Entity\Category $categories
*/
public function removeCategory(Category $categories) {
$this->categories->removeElement ( $categories );
}
/**
* Get categories
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getCategories() {
return $this->categories;
}
/**
* Add applications
*
* @param \OC\PlatformBundle\Entity\Application $applications
* @return Advert
*/
public function addApplication(\OC\PlatformBundle\Entity\Application $applications) {
$this->applications [] = $applications;
$applications->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->applications->removeElement ( $applications );
}
/**
* Get applications
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getApplications() {
return $this->applications;
}
public function listAction() {
$listAdverts = $this->getDoctrine ()->getManager ()->getRepository ( 'OCPlatformBundle:Advert' )->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->getApplications ();
}
// …
}
/**
* Set updatedAt
*
* @param \DateTime $updatedAt
* @return Advert
*/
public function setUpdatedAt($updatedAt) {
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Get updatedAt
*
* @return \DateTime
*/
public function getUpdatedAt() {
return $this->updatedAt;
}
/**
* @ORM\PreUpdate
*/
public function updateDate() {
$this->setUpdatedAt ( new \DateTime () );
}
public function increaseApplication() {
$this->nbApplications ++;
}
public function decreaseApplication() {
$this->nbApplications --;
}
/**
* Set nbApplications
*
* @param integer $nbApplications
* @return Advert
*/
public function setNbApplications($nbApplications) {
$this->nbApplications = $nbApplications;
return $this;
}
/**
* Get nbApplications
*
* @return integer
*/
public function getNbApplications() {
return $this->nbApplications;
}
/**
* Set slug
*
* @param string $slug
* @return Advert
*/
public function setSlug($slug) {
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* @return string
*/
public function getSlug() {
return $this->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->getContent())) {
// // La règle est violée, on définit l'erreur
// // $context
// // ->buildViolation('Contenu invalide car il contient un mot interdit.') // message
// // ->atPath('content') // attribut de l'objet qui est violé
// // ->addViolation() // ceci déclenche l'erreur, ne l'oubliez pas
// // ;
// $context->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>