Chapters
-
Course Code
Subscribe to download the code!Compatible PHP versions: ^7.1.3
Subscribe to download the code!Compatible PHP versions: ^7.1.3
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Validation Constraints with @Assert
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeWhen you talk about validation, what you're really talking about is business rules validation. That's where you tell Symfony that the title is required and needs to be a certain length, or that some field should be a valid email address, or that the password must contain 2 upper case letters, 2 lower case letters, 3 unicode characters and at least 4 emojis. It's about making the data constrain to your application's rules.
Adding your First Assert Annotation
Symfony's validation is kinda interesting because you do not apply the validation rules to the form. Nope, you apply them to your class via annotations. Check this out: I want the title
field to be required. To do that, type @NotBlank
and hit tab to autocomplete to @Assert\NotBlank
. Because I have the PHP annotations plugin installed, when I auto-completed that, it added a use
statement on top that we need: use Symfony\Component\Validator\Constraints as Assert
.
Show Lines
|
// ... lines 1 - 11 |
use Symfony\Component\Validator\Constraints as Assert; | |
Show Lines
|
// ... lines 13 - 16 |
class Article | |
{ | |
Show Lines
|
// ... lines 19 - 27 |
/** | |
Show Lines
|
// ... line 29 |
* @Assert\NotBlank() | |
*/ | |
private $title; | |
Show Lines
|
// ... lines 33 - 255 |
} |
Without doing anything else, refresh the form - the title
field is empty. Yes! That's our error!
This value should not be blank.
To customize that, add a message
key to the annotation:
Get creative and think of a title!
Show Lines
|
// ... lines 1 - 27 |
/** | |
Show Lines
|
// ... line 29 |
* @Assert\NotBlank(message="Get creative and think of a title!") | |
*/ | |
private $title; | |
Show Lines
|
// ... lines 33 - 257 |
Try it again - refresh and... nice!
The Built-in Validation Constraints
On the docs, click to go back to the documentation homepage. Then, under guides, find the "Validation" guide. Just like with the form fields, there are a bunch of built-in validation constraints that... can help you validate almost anything! And... just like with form field types, each validation constraint has different options that control its behavior.
For example - check out Length
: you can set the min
length with the min
option, or max
with max
. Control their error messages with minMessage
and maxMessage
.
Oh, another way to see what the options are is to remember that every annotation has a concrete PHP class behind it. Thanks to the PHP annotations plugin, I can hold Command or Ctrl and click the annotation to jump to that class.
Nice! Every property becomes an option that you can pass to the annotation. We'll see this again later when we create our own custom validation constraint.
Anyways, we won't talk too much about validation constraints because... they're honestly pretty easy: it's usually a matter of finding which validation constraint you need and the options to pass to it.
The Callback Constraint
Oh, but there is one really cool constraint called Callback
. This is the tool when you need to go rogue and do something totally custom. Check it out: create a method in your class and add @Assert\Callback()
above it. Then, during validation, Symfony will call your method!
Let's copy this, find our Article
class, go all the way to the bottom, and paste. Oh, I need to retype the end of ExecutionContextInterface
and auto-complete it to get the use
statement. Then, inside... it's awesome! We can do whatever we want!
Show Lines
|
// ... lines 1 - 12 |
use Symfony\Component\Validator\Context\ExecutionContextInterface; | |
Show Lines
|
// ... lines 14 - 17 |
class Article | |
{ | |
Show Lines
|
// ... lines 20 - 257 |
/** | |
* @Assert\Callback | |
*/ | |
public function validate(ExecutionContextInterface $context, $payload) | |
{ | |
Show Lines
|
// ... lines 263 - 267 |
} | |
} |
Let's make sure that the title
of this Article
doesn't contain the string the borg
... cause they're scary. So, if stripos()
of $this->getTitle()
and the borg
does not equal false... error! To create the error, use $context->buildViolation()
:
Um.. the Borg kinda makes us nervous
Apparently so nervous that I typed "the Bork" instead! Resistance to typos is futile...
Next, choose which field to attach the error to with ->atPath('title')
and finish with ->addViolation()
. That's it!
Show Lines
|
// ... lines 1 - 260 |
public function validate(ExecutionContextInterface $context, $payload) | |
{ | |
if (stripos($this->getTitle(), 'the borg') !== false) { | |
$context->buildViolation('Um.. the Bork kinda makes us nervous') | |
->atPath('title') | |
->addViolation(); | |
} | |
} | |
Show Lines
|
// ... lines 269 - 270 |
Go back to our form, write an article about how you really want to join the borg and Create!
Got it! Custom validation logic with a custom error.
Next: let's talk a little more about how we can control the rendering of these fields. Because, right now, we're just sort of rendering them all at once... without much control over their look and feel.
33 Comments
Hey Omar,
In this case, you need to add another constraint, the "NotNull" constraint https://symfony.com/doc/current/reference/constraints/NotNull.html
Cheers!
@Assert\NotBlack(message="Please fill in ..")
Messsage is not working. It keeps saying 'Example invalid select feedback' underneath input fields. Also the little red Error label is not showing.
Hey Farry7,
Haha, it makes sense, as it says "NotBlack" but your would need "NotBlank" ;) I'd recommend you to use PhpStorm with enabled Symfony plugin for autocompletion class names, it may help avoiding such problems. Btw, don't forget about using the correct namespace for that constraint as well!
Cheers!
use Symfony\Component\Validator\Context\ExecutionContextInterface;
undefined namescpace "Contenxt" when I mouseover it on PHPStorm.
It doesnt work.
Hey @Farry7!
Hmm, that's interesting. That IS the correct namespace & interface name - you can see in, for example, Symfony 5.2 right here: https://github.com/symfony/...
Do you see a vendor/symfony/validator directory in your project? If it's not, make sure you install it - like we do here https://symfonycasts.com/sc...
Cheers!
Hello, How to add two atPath () ?, I tried to put -> atPath ('firstName')->atPath('lastName').is working just for one field :/
Hey Med,
I'm afraid you cannot do this. The 2nd call of atPath() will override the previous value. What are you trying to achieve? Display the same message for a few fields? Try to build another second violation for this, like:
$errorMessage = '%Your error message here%';
$context->buildViolation($errorMessage)
->atPath('firstName')
->addViolation();
$context->buildViolation($errorMessage)
->atPath('lastName')
->addViolation();
Just put your error message on a variable and use it to avoid duplications if needed.
I hope this helps!
Cheers!
Thank you for your answer, I want to display the same error message for two different fields.
If I put a second violation I would have two identical messages for the two fields and I want only one error message: /
Message error : FirstName or lastName can't be null
Hey Med,
Try to set the error message for the 2nd field only, the it should look good I think. Otherwise, you can think of splitting this error message into 2 separate about first name and last name. As an alternative, you can skip atPath() call and apply this error to the whole form instead of the specific field. This is more relevant for what you're trying to do - a general error for the whole form. If none of this fits you - go to the template and render your form yourself with form_error(), form_label(), form_widget() Twig functions. This will give you flexibility and you will render the error wherever you want.
I hope this helps!
Cheers!
So following this I can't seem to switch off the html5 validation to get the custom message fo blanl - I just get the browser instructing value cannot be empty
Ah you needed to add 'required' => false - perfect!
"you do not apply the validation rules to the form" - you can apply to the form as I understand https://symfony.com/doc/4.4...
Hey Coder,
Yes, you can apply validation rules to entities or to form types. General rules better apply to entities because those rules will work for all forms. But if you want to apply a specific rule for a specific form - you can do it too in the form type.
Cheers!
Hey Vali,
Good question! Actually, IIRC they should not override each other, they should "summarize". Like Validator will check both validation constraint you declared in your entity and in form type. You can easily double-check this ;)
Cheers!
Hi,
I put @Assert\NotBlank() on the private $title property of the Article class but when I refresh I haven't the error message like you: "Error the value should not be blank". Can you explain me how I can solve that?
Hey, don't forget to get the "required" field blank (with the inspector) or make your <input> novalidate into html :p
Hey @stephansav,
Are you just refreshing page? or re-submitting form? You should submit form again, because assertion works only when form is submitted
Cheers!
Hi everyone !
I did @Assert on all my entities and that my form works. But what if I wanna use Ajax to display the data in a modal before submitting them ? How can I make the error messages appear then ? (Because I did it but since Ajax calls, reload is not happening and thus no error message are displayed. Any hint ?
I am lost :'(
Thanx
Hey Marine GREGOIRE
You will need to implement an endpoint where you can submit the form's data, validate the fields and finally return the form's HTML. It would be almost the same logic as you already do but instead of doing "some" logic, such endpoint will always return the rendered form. Does it make any sense to you?
Cheers!
Hi everyone!
I´m just getting started with symfony and I'm trying out this Assert validation stuff...
I'm trying to make a field not empty and unique name with the following code:
class Portals
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(name="name", type="string", length=255)
* @Assert\NotBlank(message="El portal debe tener un nombre.")
* @Assert\Unique(message="Este nombre ya existe")
*
*/
private $name;
And when I submit the form I get an "This value should be of type array|IteratorAggregate" no matter what I type in the field, it doesn't matter if the name already exists on the database or not, it just never goes through! is this a bug on 4.3??? Am I missing something???
Thanks for your help in advance!
-Orallo
Hey Jose M.
You are using the wrong constraint for your goal. Give it a look on the docs: https://symfony.com/doc/current/reference/constraints/Unique.html
that Unique
constraint is for collections, the one you are looking for is UniqueEntity
and it applies over the class. I'll leave you the docs here: https://symfony.com/doc/current/reference/constraints/UniqueEntity.html but if you have more doubts, let us know :)
Cheers!
Hello!
Also regarding Automatic validation as described in link bellow
https://symfony.com/blog/ne...
Can you please explain how to make it work.
I have symfony 4.3 application, currently create Entities,
really do not want to add Validator annotations manually.
Lets say I have a field notNull
/**
* @var string
* @ORM\Column(name="title", type="string", length=10, nullable=false)
*/
private $title;
and in controller
leaving title property empty and validating
$errors = $validator->validate($post);
finds no errors.
Thanks!
Avraham
Hey Avraham,
First of all, you need to upgrade your Symfony application to the latest 4.3 version, the version we use in this screencasts does not support it yet. Then, follow the instructions in that blog post you linked. And finally, you would need to enable this feature in your config/packages/validator.yaml like:
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\: []
And then it should work I think. But it has an issue IIRC, you can follow this thread to get more information why it's not enabled by default:
https://github.com/symfony/recipes/pull/612
I hope this helps!
Cheers!
Hey Victor!
Uncommenting
auto_mapping:
App\Entity\: []
from validator.yaml enabled Automatic validation!!!
Github discussion say this caused issue with forms
https://github.com/symfony/...
Yet Automatic Validation works.
Thank you very much!
Hey Avraham,
Great, glad it works for you. This is an awesome new feature indeed.
Cheers!
Hello Guys I need your help, recently we have updated to Symfony 4.3 where new feature was introduced for auto validation.
I now I have new issues... or I need some extra explanation or there is a bug...
In my entity I have such definition for a property:
`
/**
- @ORM\Column(type="string", length=128)
- @Assert\NotBlank()
*/
private $tag;
public function getTag(): ?string
{
return $this->tag;
}
public function setTag(string $tag): self
{
$this->tag = $tag;
return $this;
}
`
With such setup like above when I edit entity and submit empty value I got following error: "This value should be of type string." previously I had (Symfony 4.2): "This value should not be blank."
But when I create new entity I get correct error message, somehow behaviour for create and edit is different in Symfony 4.3?
Why my validators do not have priority, why these automatic ones are executed first?
Also I have noticed that if I will remove type (string) form setter then this works and I get correct message. Should I then remove these from all my entities?
How can I overwrite this message automatic message: This value should be of type string.
How I can disable this functionality in my project?
Hey Krzysztof
For translating validation messages you can follow this guide: https://symfony.com/doc/current/validation/translations.html
And for disabling the auto validation system. Hmm, If I recall correctly it should be disabled by default but I believe you can disable it by changing the "framework.validation" configuration
// config/packages/validation.yaml
framework:
validation:
auto_mapping: []
Give it a try and let us know if it worked.
Cheers!
Diego
Thanks Victor, but what about validation priority? Can my validator be executed first? I was unable to find any additional info about this new feature.
Hey Krzysztof,
What do you mean? What your validator exactly? Fairly speaking, I'm not sure there's any priorities in applying validation constraints, maybe try to change their order? They might be applied in order how they are declared.
I hope this helps!
Cheers!
Guys, any news on above?
Hey Krzysztof,
Oh, thanks for this ping! Our teammate Diego replied to you the next day, but somehow that message get lost, I restored it from the history, see the answer here: https://symfonycasts.com/sc...
We're sorry about it!
Cheers!
"Houston: no signs of life"
Start the conversation!
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": "^7.1.3",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/annotations": "^1.0", // 1.10.2
"doctrine/doctrine-bundle": "^1.6.10", // 1.10.2
"doctrine/doctrine-migrations-bundle": "^1.3|^2.0", // v2.0.0
"doctrine/orm": "^2.5.11", // v2.7.2
"knplabs/knp-markdown-bundle": "^1.7", // 1.7.0
"knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
"knplabs/knp-time-bundle": "^1.8", // 1.8.0
"nexylan/slack-bundle": "^2.0,<2.2.0", // v2.0.0
"php-http/guzzle6-adapter": "^1.1", // v1.1.1
"phpdocumentor/reflection-docblock": "^3.0|^4.0", // 4.3.0
"sensio/framework-extra-bundle": "^5.1", // v5.2.1
"stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
"symfony/asset": "^4.0", // v4.1.6
"symfony/cache": "^3.3|^4.0", // v4.1.6
"symfony/console": "^4.0", // v4.1.6
"symfony/flex": "^1.0", // v1.21.6
"symfony/form": "^4.0", // v4.1.6
"symfony/framework-bundle": "^4.0", // v4.1.6
"symfony/property-access": "^3.3|^4.0", // v4.1.6
"symfony/property-info": "^3.3|^4.0", // v4.1.6
"symfony/security-bundle": "^4.0", // v4.1.6
"symfony/serializer": "^3.3|^4.0", // v4.1.6
"symfony/twig-bundle": "^4.0", // v4.1.6
"symfony/validator": "^4.0", // v4.1.6
"symfony/web-server-bundle": "^4.0", // v4.1.6
"symfony/yaml": "^4.0", // v4.1.6
"twig/extensions": "^1.5" // v1.5.2
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.0", // 3.0.2
"easycorp/easy-log-handler": "^1.0.2", // v1.0.7
"fzaninotto/faker": "^1.7", // v1.8.0
"symfony/debug-bundle": "^3.3|^4.0", // v4.1.6
"symfony/dotenv": "^4.0", // v4.1.6
"symfony/maker-bundle": "^1.0", // v1.8.0
"symfony/monolog-bundle": "^3.0", // v3.3.0
"symfony/phpunit-bridge": "^3.3|^4.0", // v4.1.6
"symfony/stopwatch": "^3.3|^4.0", // v4.1.6
"symfony/var-dumper": "^3.3|^4.0", // v4.1.6
"symfony/web-profiler-bundle": "^3.3|^4.0" // v4.1.6
}
}
Hey I am using Symfony 6 with Php 8,
When I use the
NotBlanck
assert for example:and add the "novalidate" on the form and submit, I get "HTTP 500 Error" with the following message:
Expected argument of type "string", "null" given at property path "username".
The problem is that the assert is never reached, there are 2 possible solutions:
Add a "?" to the setter parameter:
Add "empty_data" value to the form builder:
But I don't find it very convenient to use these solutions on almost every filed on every entity!
My question is what is the best practice for this situation? Knowing that in the normal flow for normal users, they will get the HTML5 error "please fill out this field". Only the bad users will try to do this and will get the 500 Error.