Validating unsubmitted form (only $form->isValid()) is now deprecated and will be removed in 4.0. You should use $form->isSubmitted && $form->isValid();
is there any reason why nobody adds method to symfony to print all those errors which you showed in the video? Or are people lazy to add ? it really acts unexpectedly when you call standard getErros method and you know there is error but you cannot see which one.
I believe the method behaves the way it does mostly for historical and some internal reasons. There was actually a GitHub issue about this opened within the past year that i agree with - it’s just confusing. You can call getErrors(true) to get all the errors, but it’s not obvious. It also doesn’t keep the key of where the error came from... so it’s not ideal.
So, from a DX point of view, I think this is something we should improve so that devs have less WTF. From an API perspective, there is now support for serializing validation errors. Basically, if you use the validator directly (not through the form system) you can serialize the errors through the Symfony validator and it will turn into really nice JSON.
Can we get more information about this error "This form should not contain extra fields." ? Mostly I misspell name of the field in json. And this always takes too much time to figure it out which field.
Symfony's Form Component doesn't allow you to have more fields than the ones you have specified in your form type, but you can configure that behaviour by using the "option resolver"
//your FormType class
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'allow_extra_fields' => true
]);
}
Understand. But I think about diffrent case. Like a have a form with field "name". When I send a POST with JSON {"naem": "value} - so I misspell, "naem" -> should be "name". I get information "This form should not contain extra fields." But better info would be something like this -> "naem field do not exist".
I have written a function to get information about "extra fields" in form. Maybe it will be usefull for others. I think it's must have for every API on Symfony form. public function throwValidationErrorsResponse(FormInterface $form, Request $request) { $jsonData = $request->getContent();
$arrayData = json_decode($jsonData, true);
$data = array_flip($arrayData);
$children = $form->all();
$arr = [];
foreach ($children as $ch) { $arr []= $ch->getName(); }
$data = array_diff($data, $arr);
$errors = $this->getErrorsFromForm($form);
array_push($errors, ['extra_fields' => $data]);
$apiProblem = new ApiProblem( 400, ApiProblem::TYPE_VALIDATION_ERROR ); $apiProblem->set('errors', $errors);
Hello, please, I need help When I write in the cmd: > php bin/phpunit -c app/ --filter testValidationErrors
I've got this instead of result testValidationErrors() What does it mean? And how I can to fix this?
dir=$(d=${0%[/\\]*}; cd "$d"; cd "../vendor/phpunit/phpunit" && pwd)
# See if we are running in Cygwin by checking for cygpath program if command -v 'cygpath' >/dev/null 2>&1; then # Cygwin paths start with /cygdrive/ which will break windows PHP, # so we need to translate the dir path to windows format. However # we could be using cygwin PHP which does not require this, so we # test if the path to PHP starts with /cygdrive/ rather than /usr/bin if [[ $(which php) == /cygdrive/* ]]; then dir=$(cygpath -m "$dir"); fi fi
dir=$(echo $dir | sed 's/ /\ /g') "${dir}/phpunit" "$@"
In Linux, the bin/phpunit file is sym-link to a PHP file, so you can execute it by saying php bin/phpunit or ./bin/phpunit. But on Windows, this is a .bat file, and so it needs to be executed with the ./ syntax. Basically, I should always use the ./bin/phpunit syntax. So, probably my mistake!
I haven't used the code from this tutorial, but my own project codes, I have done the similar setting as this tutorial, the $response come back with right 400 statusCode and right response body. However, my test cannot be passed and the assertion part haven't been reached (namely, there are some errors before I could do the assertions). I then tried to use try{} catch(){} to catch the $exception body, the return content are the same as : { "type": "validation_error", "title": "There was a validation error", "errors": { "birthday": [ "Please input your birthday." ] } } But the test just never pass.
This is the error details below: Failure! when making the following request: POST: http://localhost:8000/api/register
HTTP/1.1 400 Bad Request Host: localhost:8000 Connection: close X-Powered-By: PHP/7.0.14 Cache-Control: no-cache Content-Type: application/json Date: Tue, 21 Mar 2017 00:09:54 GMT { "type": "validation_error", "title": "There was a validation error", "errors": { "birthday": [ "Please input your birthday." ] } } E 1 / 1 (100%)
My project used the FOSUserBundle, and when I tried to use the Browser to see what $response return, it appears as below: {"type":"validation_error","title":"There was a validation error","errors":{"email":["Please enter an email."],"username":["Please enter a username."],"plainPassword":{"first":["Please enter a password."]},"birthday":["Please input your birthday."]}}
In the $data array, I DO input 'email'/'username' and 'plainPassword'. I spent lots of time on google to find a solution for my case, but I haven't find anything helpful.
Do you have any idea about this? Any help will be appreciated!!!
The GET request from browser won't get the $data array, that's why my browser returns more fields than a POST request from Guzzle;
I used the
try{/*your requests*/}
catch (ClientException $e){
$response = $e->getResponse();
//verify assertions here, although it's a bit odd as some assertor() functions doesn't work properly
}
I suspect it's the guzzle version issue, it threw 400 error (as it should) before assertions codes were reached so I failed my test. I am a RESTful newbie, if it's not right, please let me know, cheers! :)
Sorry for my late reply, but even better you figured it out for yourself. You're 100% correct on (1) - that's part of the reason we have some "tricks" in our base test class to help print the response in the terminal - it's not always something you can see just by going to the browser!
About (2), by default, Guzzle throws an exception whenever the response is a 400 or 500 status code. However, in ApiTestCase, we add some configuration that says to NOT do this, as it makes testing a bit more difficult. I see you're using Guzzle 6 - check out the code download for episode 4 of this series (where the code has been upgraded to Guzzle 6) - you'll see the http_errors => false line that configures our client this way). Did you possibly change the ApiTestCase code to use new Guzzle, but without this option? It's really fine either way - you can let Guzzle throw exceptions or turn them off - obviously, it just changes how your code will look :).
Yes, I modified the codes from your tutorials to fit my project, they works like a charm now. Thanks for all these efforts, I learnt a lot from you. I will carry on to buy more after I finish these big tricky part, very helpful and interesting, thanks again to your team and you for these brilliant works!
Ah, lame! Hmm, it looks like that error usually comes when you're trying to decode a date or do something (like multiplication) with a non-number... but I can't think of where we would be sing that!
So, let's do some debugging! First, do you always get this error no matter what values you fill in for your fields? Second, can you use the tricks on this page - https://knpuniversity.com/s... - to see if you can see a stacktrace for the error? I'm sure if we can see a stracktrace (if you find it, you could take a screenshot or copy-paste), I'm sure we'll be able to hunt down the cause!
Ryan, did some digging myself as i ran into the same problem. i have my CLI running PHP 7.1 by default. Found this PR request for symfony 2.7 https://github.com/symfony/.... seems like this is the problem.
To fix the issue i just changed the composer file to read the following:
Wow, nice find! Thanks for sharing it - that's super subtle :)
Cheers!
Please, log in to vote for this comment
|
Share Comment
"Houston: no signs of life" Start the conversation!
This tutorial uses an older version of Symfony. The concepts of REST and errors are still valid, but I recommend using API Platform in new Symfony apps.
24 Comments
Hello,
Validating unsubmitted form (only $form->isValid()) is now deprecated and will be removed in 4.0. You should use $form->isSubmitted && $form->isValid();
Hi Robert,
Good catch! We have to add a note about it, but I think it would be done in the Symfony Forms tutorial.
Thank you for this notice!
Cheers!
"Let's just pretend I made that mistake on purpose".
Riiiight
is there any reason why nobody adds method to symfony to print all those errors which you showed in the video? Or are people lazy to add ? it really acts unexpectedly when you call standard getErros method and you know there is error but you cannot see which one.
Hey @Coder!
You’re totally right - isn’t that strange? :)
I believe the method behaves the way it does mostly for historical and some internal reasons. There was actually a GitHub issue about this opened within the past year that i agree with - it’s just confusing. You can call getErrors(true) to get all the errors, but it’s not obvious. It also doesn’t keep the key of where the error came from... so it’s not ideal.
So, from a DX point of view, I think this is something we should improve so that devs have less WTF. From an API perspective, there is now support for serializing validation errors. Basically, if you use the validator directly (not through the form system) you can serialize the errors through the Symfony validator and it will turn into really nice JSON.
I hope that explains it a bit - great question!
Can we get more information about this error "This form should not contain extra fields." ? Mostly I misspell name of the field in json. And this always takes too much time to figure it out which field.
Hey Slawek!
Symfony's Form Component doesn't allow you to have more fields than the ones you have specified in your form type, but you can configure that behaviour by using the "option resolver"
Have a nice day!
Understand. But I think about diffrent case. Like a have a form with field "name". When I send a POST with JSON {"naem": "value} - so I misspell, "naem" -> should be "name". I get information "This form should not contain extra fields." But better info would be something like this -> "naem field do not exist".
Ohh I got you now!
Look's like Symfony doesn't do it by default, in that case you would have to validate every form field by hand and add the desired error message to it
Cheers!
I have written a function to get information about "extra fields" in form. Maybe it will be usefull for others. I think it's must have for every API on Symfony form.
public function throwValidationErrorsResponse(FormInterface $form, Request $request)
{
$jsonData = $request->getContent();
$arrayData = json_decode($jsonData, true);
$data = array_flip($arrayData);
$children = $form->all();
$arr = [];
foreach ($children as $ch) {
$arr []= $ch->getName();
}
$data = array_diff($data, $arr);
$errors = $this->getErrorsFromForm($form);
array_push($errors, ['extra_fields' => $data]);
$apiProblem = new ApiProblem(
400,
ApiProblem::TYPE_VALIDATION_ERROR
);
$apiProblem->set('errors', $errors);
throw new ApiProblemException($apiProblem);
}
I have found a little bug. But here is the fix:
$jsonData = $request->getContent();
$arrayData = json_decode($jsonData, true);
$arrayForm = $form->all();
$data = array_diff_key($arrayData, $arrayForm);
$errors = $this->getErrorsFromForm($form);
if($data){
array_push($errors, ['extra_fields' => $data]);
}
$apiProblem = new ApiProblem(
400,
ApiProblem::TYPE_VALIDATION_ERROR
);
$apiProblem->set('errors', $errors);
throw new ApiProblemException($apiProblem);
Thanks for sharing your solution, I bet someone will find it useful ;)
Cheers!
Hello, please, I need help
When I write in the cmd:
> php bin/phpunit -c app/ --filter testValidationErrors
I've got this instead of result testValidationErrors()
What does it mean? And how I can to fix this?
dir=$(d=${0%[/\\]*}; cd "$d"; cd "../vendor/phpunit/phpunit" && pwd)
# See if we are running in Cygwin by checking for cygpath program
if command -v 'cygpath' >/dev/null 2>&1; then
# Cygwin paths start with /cygdrive/ which will break windows PHP,
# so we need to translate the dir path to windows format. However
# we could be using cygwin PHP which does not require this, so we
# test if the path to PHP starts with /cygdrive/ rather than /usr/bin
if [[ $(which php) == /cygdrive/* ]]; then
dir=$(cygpath -m "$dir");
fi
fi
dir=$(echo $dir | sed 's/ /\ /g')
"${dir}/phpunit" "$@"
Hey Nina!
That's probably my mistake :). Try this instead:
In Linux, the bin/phpunit file is sym-link to a PHP file, so you can execute it by saying
php bin/phpunitor./bin/phpunit. But on Windows, this is a .bat file, and so it needs to be executed with the./syntax. Basically, I should always use the./bin/phpunitsyntax. So, probably my mistake!Let me know if it helps! And cheers!
Hi, Ryan,
May I ask you a question, please?
I haven't used the code from this tutorial, but my own project codes, I have done the similar setting as this tutorial, the $response come back with right 400 statusCode and right response body. However, my test cannot be passed and the assertion part haven't been reached (namely, there are some errors before I could do the assertions). I then tried to use try{} catch(){} to catch the $exception body, the return content are the same as :
{
"type": "validation_error",
"title": "There was a validation error",
"errors": {
"birthday": [
"Please input your birthday."
]
}
}
But the test just never pass.
This is the error details below:
Failure! when making the following request:
POST: http://localhost:8000/api/register
HTTP/1.1 400 Bad Request
Host: localhost:8000
Connection: close
X-Powered-By: PHP/7.0.14
Cache-Control: no-cache
Content-Type: application/json
Date: Tue, 21 Mar 2017 00:09:54 GMT
{
"type": "validation_error",
"title": "There was a validation error",
"errors": {
"birthday": [
"Please input your birthday."
]
}
}
E 1 / 1 (100%)
Time: 1.06 seconds, Memory: 8.00MB
There was 1 error:
1) MyProject\UserBundle\Tests\Controller\Api\RegistrationControllerTest::testValidationErrors
GuzzleHttp\Exception\ClientException: Client error response [url] http://localhost:8000/api/register [status code] 400 [reason phrase] Bad Request
My project used the FOSUserBundle, and when I tried to use the Browser to see what $response return, it appears as below:
{"type":"validation_error","title":"There was a validation error","errors":{"email":["Please enter an email."],"username":["Please enter a username."],"plainPassword":{"first":["Please enter a password."]},"birthday":["Please input your birthday."]}}
In the $data array, I DO input 'email'/'username' and 'plainPassword'. I spent lots of time on google to find a solution for my case, but I haven't find anything helpful.
Do you have any idea about this? Any help will be appreciated!!!
Cheers!
Sheeran
SOVLED!
I suspect it's the guzzle version issue, it threw 400 error (as it should) before assertions codes were reached so I failed my test.
I am a RESTful newbie, if it's not right, please let me know, cheers! :)
Best regards,
Sheeran
Yo Chan Sheeran!
Sorry for my late reply, but even better you figured it out for yourself. You're 100% correct on (1) - that's part of the reason we have some "tricks" in our base test class to help print the response in the terminal - it's not always something you can see just by going to the browser!
About (2), by default, Guzzle throws an exception whenever the response is a 400 or 500 status code. However, in ApiTestCase, we add some configuration that says to NOT do this, as it makes testing a bit more difficult. I see you're using Guzzle 6 - check out the code download for episode 4 of this series (where the code has been upgraded to Guzzle 6) - you'll see the
http_errors => falseline that configures our client this way). Did you possibly change the ApiTestCase code to use new Guzzle, but without this option? It's really fine either way - you can let Guzzle throw exceptions or turn them off - obviously, it just changes how your code will look :).And welcome to REST - it's tricky, but powerful!
Cheers!
Hi, Ryan,
Thanks for your reply!
Yes, I modified the codes from your tutorials to fit my project, they works like a charm now. Thanks for all these efforts, I learnt a lot from you. I will carry on to buy more after I finish these big tricky part, very helpful and interesting, thanks again to your team and you for these brilliant works!
Cheers!
Sheeran
Cheers buddy! And good luck! :)
Hi , I get this error and I cant figure out what is wrong
There was an Error!!!!
Notice: A non well formed numeric value encountered
Hey!
Ah, lame! Hmm, it looks like that error usually comes when you're trying to decode a date or do something (like multiplication) with a non-number... but I can't think of where we would be sing that!
So, let's do some debugging! First, do you always get this error no matter what values you fill in for your fields? Second, can you use the tricks on this page - https://knpuniversity.com/s... - to see if you can see a stacktrace for the error? I'm sure if we can see a stracktrace (if you find it, you could take a screenshot or copy-paste), I'm sure we'll be able to hunt down the cause!
Cheers!
Ryan, did some digging myself as i ran into the same problem. i have my CLI running PHP 7.1 by default. Found this PR request for symfony 2.7 https://github.com/symfony/.... seems like this is the problem.
To fix the issue i just changed the composer file to read the following:
....
"require": {
"php": ">=7.1",
"symfony/symfony": "2.7.*",
....
},
....
Thanks,
Jordan Wamser
Hey jmwamser!
Wow, nice find! Thanks for sharing it - that's super subtle :)
Cheers!
"Houston: no signs of life"
Start the conversation!