Chapters
28 Chapters
|
2:24:59
|
Login to bookmark this video
-
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!
24.
Embedded Form Validation with @Valid
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part 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.
This course is built on Symfony 3, but most of the concepts apply just fine to newer versions of Symfony.
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": "^7.1.3",
"symfony/symfony": "3.4.*", // v3.4.49
"doctrine/orm": "^2.5", // 2.7.5
"doctrine/doctrine-bundle": "^1.6", // 1.12.13
"doctrine/doctrine-cache-bundle": "^1.2", // 1.4.0
"symfony/swiftmailer-bundle": "^2.3", // v2.6.7
"symfony/monolog-bundle": "^2.8", // v2.12.1
"symfony/polyfill-apcu": "^1.0", // v1.23.0
"sensio/distribution-bundle": "^5.0", // v5.0.25
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.29
"incenteev/composer-parameter-handler": "^2.0", // v2.1.4
"composer/package-versions-deprecated": "^1.11", // 1.11.99.4
"knplabs/knp-markdown-bundle": "^1.4", // 1.9.0
"doctrine/doctrine-migrations-bundle": "^1.1", // v1.3.2
"stof/doctrine-extensions-bundle": "^1.2" // v1.3.0
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.1.7
"symfony/phpunit-bridge": "^3.0", // v3.4.47
"nelmio/alice": "^2.1", // v2.3.6
"doctrine/doctrine-fixtures-bundle": "^2.3" // v2.4.1
}
}
14 Comments
Hi guys, not sure you are dealing with in another chapter/course but the UniqueEntity validation does not work on the "new genus" page. Is this covered somewhere and I might have missed it?
Thanks!
I just found out this:
So I guess custom validation is the way to go; Any hints/links on this one are greatly welcome :)
Hey christosp
That constraint comes shipped with Symfony since version 4.3. Give it a check: https://symfony.com/blog/ne...
Cheers!
Hi,
I am trying to apply same structure to the similar project. However I came to an issue using @UniqueEntity. The issue arises when I have more than 1 scientist working on genus, then remove the first scientist (lets say aquanaut1@example.org), and then add it again as the last one. I can see that removeGenusScientist function is called and later addGenusScientist function is called, but I still get an "This user is already studying this genus" error under aquanaut1@example.org. How to fix this bug?
Thank you in advance!
Hey Justas!
If I understand correctly, you added 2 scientists to the Genus *before* configuring the UniqueEntity validation. And then, after adding UniqueEntity, you get this weird behavior. Is that correct? If so, I've seen this as well - I think because you're *starting* with your system in an invalid state (a state that would never be allowed if UniqueEntity were used), UniqueEntity gets confused. In the real world, you should of course always have UniqueEntity from the beginning, so you won't fall into this situation. But yea, I think there *is* some weird behavior if your system starts in this invalid state. How to fix it? Ideally, you don't need to :)... because you will use UniqueEntity to never allow this. But if you have an existing database with duplications and are now adding UniqueEntity, then you can either (A) run some sort of database migration to remove the duplicates or (B) create your own custom constraint instead of using UniqueEntity - I think UniqueEntity will always act in this way.
Cheers!
Hi Ryan,
The problem is not caused by invalid state. You can remove all the scientists, save. Then add scientist1 and scientist2, save. Then when you edit the form again (you will see scientist1 and scientist2), remove the first scientist, without saving add a new one and select scientist1 again. In the form you will see scientist2 and scientist1, then try to save. It will not let you save the form saying that scientist1 is already working on the genus. Basically if you switch the order of the scientist in the collection the unique error appears.
Hey Justas!
Ah, I see! And I can repeat the issue. Here's the problem:
Suppose you start with 2 scientists: scientist1 (e.g. GenusScientist id 5) and scientist2 (GenusScientist id 6). But, you delete scientist1 from the form and re-add him (just like you described). When you submit:
1) the UniqueEntity constraint queries the database *two* times: once to see if there is already a GenusScientist with the same user+genus as scientist1 and once to see if there is already a GenusScientist with the same user+genus as scientist2. In both cases, a result is returned: GenusScientist id 5 for "scientist1" and GenusScientist id 6 for "scientist 2"
2) the UniqueEntity constraint then checks to see if the queried GenusScientist matches exactly (===) the object that it was checking again... because if there was only 1 match found... it might be *this* GenusScientist, so it shouldn't be a duplicate. For "scientist 2", it compares GenusScientist id 6 with the one from the query, GenusScientist id 6. These are ===, so it does not create a validation constraint. BUT, for "scientist 1", it compares two GenusScientist objects that are *almost* (but not quite) identical. They have all the same fields... except for "id": the one from the database of course has id 6, but the one that was just submitted has a *null* id - because this was just created by our form system. Hence, a validation error is added.
So, that's the problem :/. This issue might be related: https://github.com/symfony/.... How can we fix it? Ideally, we'd like our form to NOT create a *new* GenusScientist when one is simply removed and then re-added. The only way I can think to do this, however, would be to add some extra JS code that when the user creates a *new* scientist and assigns a user that was previously in the form, you actually dynamically update its "name" index to match the original one. In the above example, "scientist1" would originally have index 0. When you re-add it, it would have index 2. You would need to detect when the user drop-down is changed to "scientist1" and dynamically reset the index to 0. Then, when you submit, it will not look like a *new* entity anymore. Of course, that's a pretty ugly solution :). The only other alternative I can think of is to not use the UniqueEntity validator and write your own - something that looked at the "genusScientists" property directly, and checked the entire array to see if there were duplicates, before saving.
I'm not sure there's a bug in the UniqueEntity validator... but certainly because of the way it's all setup, it just doesn't have enough knowledge to get things "perfect" for our situation.
Let me know if that helps! Cheers!
And actually, a good way to do that custom constraint might just be to do a Callback constraint on the Genus entity - you could easily loop through genusScientists to see if there are any duplicates. If that works (seems like it should), that would be a super simple solution!
Hi,
I'm using Symfony 3.2.6. The problem of Collection Type is Error message on the top which may be fixed in this version. Is it right ?
Hey TamNC!
Are you talking about the UniqueEntity error ? if that the case, remember to set up the "errorPath" option to the user field, so it will appear inside the user input field.
Have a nice day!
After adding the Bug fix in my code, it shows this error instead:
"Catchable Fatal Error: Argument 1 passed to AppBundle\Form\GenusFormType::onPreSubmit() must be an instance of AppBundle\Form\FormEvent, instance of Symfony\Component\Form\FormEvent given"
any similar encounter?
Hey Louis,
You have a good tip in this error message: you just have to use the "Symfony\Component\Form\FormEvent" namespace in the GenusFormType class. ;)
Cheers!
Hi, I came accross this course while searching for a solution for my "edge case".
@Assert\Valid() at the parent object works if the validation on the embedded object is static - I mean the validation is for every embedded object the same.
I'm looking for a solution to validate the embedded objects depending on a single value of each embedded object.
E.g. the embedded object (or entity) consists of a type field, address fields (city, zip, street) and a description field. Depending on the type either the address fields are mandatory or the description field is mandatory.
I tried it via closure at the embedded form, but as you note within this course, Symfony reads only the annotation validation from the top level class.
Hey Marcus
In that case you will have to define your constraints directly in every parent FormType, so can customize them as you need, something like this:
if you need to do more logic, you may want to take a look at Form Events: https://symfony.com/doc/current/form/events.html
Cheers!
"Houston: no signs of life"
Start the conversation!