I have a formular that I want to validate. The user should not be able to leave fields unfilled and that why I use #Assert\NotBlank but it does not seem to be working this is a part of my entity:
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
...
/**
* #var string
*
* #ORM\Column(name="device", type="string", length=255, nullable=false)
* #Assert\NotBlank(message="This value cannot be empty!")
*/
private $device;
...
And in the controler I'm using formbuilder from symfony like this:
...
$form = $this->createFormBuilder()
->add('device', 'text', array(
'label' => 'Device:',
'attr' => array('placeholder' =>'Dell 2407WPB - Monitor'),
'required' => true,
))
...
Do you have any suggestions about what may I be doing wrong? I've been stuck in this problem too long.
Thanks in advance :)
When you create the form with createFormBuilder, you should pass an instance of the entity.
$form = $this->createFormBuilder(new MyEntity())
so that the form know the class that holds the data (and his constraints).
Related
In a publishing form, a user can decide to add one or more media, they just need to copy/paste <iframe> tags into text fields.
I would like to find a solution to make sure that the user only enters valid <iframe> tags in this form.
I'm trying to use an #Assert\Regex in my entity, as below, but this doesn't work because no matter what data is entered, it is validated.
I've used the PHP Live Regex online tool to help me write this regex. On this tool, my regex seems to work well.
What's wrong with this regex?
Is using an #Assert\Regex in this case a good practice ?
namespace App\Entity;
use App\Repository\MediaRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity(repositoryClass=MediaRepository::class)
*/
class Media
{
// ...
/**
* #ORM\Column(type="string", length=255)
* #Assert\NotNull()
* #Assert\NotBlank()
* #Assert\Regex(
* pattern="/<iframe[^>]*>\s*<\/iframe>/",
* message="Please enter a valid iframe tag"
* )
*/
private $iframe;
Strangely, the regular expression constraint works when initialized from the FormBuilder, like this :
class MediaType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('iframe', TextType::class, [
'constraints' => new Regex([
'pattern' => "/^<iframe[^>]*>\s*<\/iframe>/",
'message' => "Please enter a valid iFrame tag",
])
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Media::class,
]);
}
}
I have a problem with symfony validation.
After adding NotBlank or Length to the entity validation displays a standard message for missing values(default message NotBlank). Regardless of whether the field has been filled or not.
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\OneToOne;
use Symfony\Component\Validator\Constraints as Assert;
class Employee
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=30)
* #Assert\NotBlank()
* #Assert\Length(min="3")
*/
private $name;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add("name", TextType::class, ['label'=>"Imie"])
->add("submit", SubmitType::class, ["label"=>"Licytuj"]);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOprions(OptionsResolver $resolver)
{
$resolver
->setDefaults
(
[
"data_class"=>Employee::class,
'attr'=>array('novalidate'=>'novalidate')
]
);
}
You have a naming issue. Change method name to override configureOptions method.
configureOprions => configureOptions
I couldn't find any issue with the code you posted. Most probably the issue will be on your controller code. Most probably you are loading a validated form into the view in the form load itself. For the better understanding please add your controller and view you are using. Sorry for writing this in the answer section.
I am currently creating a form that lets the user choose a certain skills from a Dropdown and a Checkbox for hobbies that lets the user check as much he/she wants.
Here is my Table for that: CurriculumVitae
/* namespace ........... */
use Doctrine\ORM\Mapping as ORM;
/**
* CurriculumVitae
*
* #ORM\Table(name="foo_cv")
* #ORM\Entity
*/
class CurriculumVitae
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
* #ORM\ManyToOne(targetEntity="Foo\BarBundle\Entity\Skills")
* #ORM\JoinColumn(name="skills", referencedColumnName="id")
*/
private $skills;
/**
* #var integer
* #ORM\ManyToOne(targetEntity="Foo\BarBundle\Entity\Hobby", cascade={"persist"})
* #ORM\JoinColumn(name="hobbies", referencedColumnName="id")
*/
private $hobby;
/* Setters and Getters ....... */
}
Here are some codes for my Form Type: CurriculumVitaeType
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('skills', 'entity', array('class' =>'FooBarBundle:Skills','property' => 'skills'))
->add('hobby', 'entity', array( 'class' => 'FooBarBundle:Hobby','property' => 'hobbies', 'expanded'=>true,'multiple'=>true, 'label' => 'hobbies'))
->add('save','submit',array('label'=>'Submit'))
;
}
/* OptionsResolverInterface ..... */
/* getName() .... */
I call my form in my twig this way in: cv.twig.html
{{ form(curriculumForm) }}
And lastly in my controller: CurriculumController
$em = $this->getDoctrine()->getManager();
$cv = new CurriculumVitae();
$curriculumForm = $this->createForm(new CurriculumVitaeType(), $cv);
$curriculumForm->handleRequest($request);
if ($curriculumForm->isValid()) {
$em->persist($cv);
$em->flush();
return $this->redirect($this->generateUrl('foo_main_window'));
}
return array('curriculumForm'=> $curriculumForm->createView());
The Form Displays correctly but when I choose a skill from the dropdown and assign a certain hobby and click on submit, an error is thrown.
Found entity of type Doctrine\Common\Collections\ArrayCollection on association Foo\BarBundle\Entity\CurriculumVitae#hobby, but expecting Foo\BarBundle\Entity\Hobby
I dont know if i missed something but i think the error occurs in the process of persisting the data after the form is submitted.
That's because you have many-to-one relation, which means
Many CurriculumVitaes can have (the same) single Hobby
But on the other hand you've created in your form a field with option 'multiple'=>true, which means that you let the user to choose multiple hobbies. Therefore form returns ArrayCollection of Hobby entites instead of single instance.
That doesn't match. You need to either remove multiple option, or make many-to-many relation on $hobby property.
I have a OneToMany relationship between Project and Application, and I want to be sure that 2 Applications cannot have the same name inside a Project.
I tried to configure my entity, form type and controller like it should be, but I am getting an Integrity contraint violation for duplicated entry, so I think the validation process is ignored.
Can someone tell me what am I missing ?
My Application entity like this :
namespace App\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use JsonSerializable;
/**
* #ORM\Entity
* #ORM\Table(name="application", uniqueConstraints={#ORM\UniqueConstraint(name="IDX_Unique", columns={"name", "project_id"})})
* #UniqueEntity(
* fields={"name", "project"},
* message="Name already used in this project.",
* groups="application"
* )
*/
class Application implements JsonSerializable {
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string")
* #Assert\NotBlank(
* message = "Name cannot be empty."
* )
* #Assert\Length(
* min = "3",
* max = "50",
* minMessage = "Name is too short. It should have {{ limit }} characters or more.",
* maxMessage = "Name is too long. It should have {{ limit }} characters or less."
* )
*/
protected $name;
// other properties ...
/**
* #ORM\ManyToOne(targetEntity="Project", inversedBy="applications")
* #ORM\JoinColumn(name="project_id", referencedColumnName="id")
*/
protected $project;
// constructor, methods, getters, setters
}
My ApplicationType class looks like this :
namespace App\MainBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ApplicationType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('name', 'text', array(
'icon' => 'pencil'
));
$builder->add('description', 'textarea', array(
'required' => false,
'icon' => 'info'
));
$builder->add('url', 'url', array(
'required' => false,
'icon' => 'link'
));
}
public function getName() {
return 'application';
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'App\MainBundle\Entity\Application',
'validation_group' => array('application'),
'cascade_validation' => true
));
}
}
And in my Controller the action looks like this:
/**
* #Route("/project/{id}/application/add",
* name="app_add_application_ajax",
* requirements={"_method" = "post"},
* options={"expose" = true }
* )
* #Secure(roles="ROLE_SUPER_ADMIN")
* #ParamConverter("project", class="AppMainBundle:Project")
*/
public function addApplicationAction(Project $project, Request $request) {
$ajaxResponse = array();
$em = $this->getDoctrine()->getManager();
if ($request->getMethod() == 'POST' && $request->isXmlHttpRequest()) {
$formApp = new Application();
$formApp->setProject($project);
$form = $this->createForm(new ApplicationType(), $formApp);
$form->handleRequest($request);
if ($form->isValid()) {
$application = $form->getData();
$em->persist($application);
$em->flush();
// build ajax response ...
} else {
$ajaxResponse['error'] = $this->getErrorsAsString();
}
}
$response = new Response(json_encode($ajaxResponse));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
Your issue is that you configure a validation_group option in your form type, while the option used by Symfony is validation_groups. You don't get an error about an unknown option because you are setting this in the default options of your form type, and so you are marking the option as defined (but it is a separate one).
So the validator runs with the default group, which will validate different constraints (the constraints on the length of the name property are in the default group).
Note that you also have a second issue, which would appear once you run the constraint.
Your validation constraint does not match the DB constraints you have. You are asking the validator to have a unique name and a unique project, not a unique tuple (name, project). So you would reject too much things (the name will be validated as unique globally, not per project).
This is because you use 2 separate UniqueEntity constraints instead of a constraint asking for a tuple of multiple fields to be unique.
I'm new on Symfony2 world. I was trying to learn the basics of Validation in Symfony2 when I ran into a problem with it. According to the guide, to manage properly a sequence of validation groups you have to add this annotation's line on your Entity class:
/**
* #Assert\GroupSequence({"User", "Strict"})
*/
And put some annotation wherever you want to handle the proper rule. In my case as well as one of the guide is the password field that should be valid only if firstly it has compiled (and respects my rules such as minimum length) and then if is different from username value. The problem is it doesnt' work for me!
I mean, I have the same User class and I used the same form of their example:
$form = $this->createFormBuilder($user, array('validation_groups' => array('signup','strict')))
->add('name', 'text')
->add('email', 'text')
->add('password', 'password')
->add('signup', 'submit')
->getForm();
Here's my User class:
<?php
namespace XXX\SiteBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* User
*
* #ORM\Table(name="users")
* #ORM\Entity
* #Assert\GroupSequence({"User", "signup", "strict"})
*/
class User
{
//..
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\NotBlank(groups={"signup"})
* #Assert\Length(min=3,groups={"signup"})
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="password", type="string", length=255)
* #Assert\NotBlank(groups={"signup"})
* #Assert\Length(min=7,groups={"signup"})
*/
private $password;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=255)
* #Assert\NotBlank(groups={"signup"})
* #Assert\Email(checkMX=true, groups={"signup"})
*/
private $email;
/**
* #Assert\True(groups={"strict"})
*/
public function isPasswordLegal()
{
return $this->name != $this->password;
}
//..some getter\setter methods
}
When I submit the form without putting values in the fields it shows me every error (and that's right) but also one that isPasswordLegal() launches, even BEFORE the others!
What am I missing? Thank you all!
The reason why the error is displayed before the others is, that you use it as a method validator and Symfony assigns the error message to the form instance and not the form field.
Edit:
All forms provide the error_mapping option which lets you define where the error messages should be shown.
In your case it would look like this:
$options = array(
'validation_groups' => array('signup','strict'),
'error_mapping' => array(
'isPasswordLegal' => 'password',
),
);
$form = $this->createFormBuilder($user, $options)
->add('name', 'text')
->add('email', 'text')
->add('password', 'password')
->add('signup', 'submit')
->getForm();