-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Validator] Added error codes to all constraints with multiple error causes #12021
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
What way to determinate what concrete constraint failed? |
Maybe can we use reflection for generation error names from constants name by they values? |
@Koc Just check Reflection is slow. We won't change the error codes very often, so an explicit mapping should be fine. |
52cb7df
to
cb35a25
Compare
@fabpot can you merge older branches into master so that this PR can be rebased ? It will be easier to review it when the diff does not include the changes of previous PRs |
I think you used the wrong issue number in your comment |
@stof No I haven't... ;) |
you cheated 😄 |
…lper for BC with the 2.4 API (webmozart) This PR was merged into the 2.5 branch. Discussion ---------- [Validator] Added ConstraintValidator::buildViolation() helper for BC with the 2.4 API | Q | A | ------------- | --- | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - This PR adds a `buildViolation()` helper method to the base `ConstraintValidator` to remove the API checks (2.4 vs. 2.5) from the constraint validator implementations. Once the 2.4 API is removed, this helper method will be removed as well. **Todos** - [x] Backport changes from #12021 Commits ------- 6b0c24a [Validator] Added ConstraintValidator::buildViolation() helper for BC with 2.4 API
cb35a25
to
7a47fa2
Compare
This is rebased now. I also improved the UUID validator to give more helpful error codes. |
Ready for review+merge. ping @symfony/deciders |
de62121
to
18d8ece
Compare
@weaverryan Could you check the names of the error constants for linguistic mistakes? |
18d8ece
to
bd4a3ed
Compare
*/ | ||
const ERR_INVALID = 1; | ||
|
||
protected static $errorNames = array( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could it be private instead ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, no sorry, forget it, it overwrites the parent ones
👍 |
*/ | ||
class CardScheme extends Constraint | ||
{ | ||
const ERROR_NOT_NUMERIC = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will cause issues in the form binding, as it checks for $allowNonSynchronized = Form::ERROR_NOT_SYNCHRONIZED === $violation->getCode();
, and Form::ERROR_NOT_SYNCHRONIZED
is 1
as well.
However, we probably need to check the violation constraint instead to ensure it is a Form constraint (we cannot be sure that the whole ecosystem will never reuse the value 1
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
7c76ac3
to
27e8f66
Compare
I changed all constant names as suggested. @weaverryan I'd still like to have a check from a native speaker, if possible. @Tobion I removed the internal flag and changed the type hint to "int" for |
27e8f66
to
c0e50a9
Compare
there are still some |
@Tobion We can't change those. Since the old
For generic code that must work with userland constraints also, you should wrap the call to |
ping @symfony/deciders I'd like to merge this today. |
c0e50a9
to
3b50bf2
Compare
…multiple error causes (webmozart) This PR was merged into the 2.6-dev branch. Discussion ---------- [Validator] Added error codes to all constraints with multiple error causes | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #7276 | License | MIT | Doc PR | TODO This PR depends on #12015 and #12016 being merged first. However, a few changes in 52cb7df first must be backported to #12016. This PR introduces error codes for all constraints with multiple error paths. This lets you determine what exactly the reason was that a constraint failed: ```php $validator = Validation::createValidator(); $violations = $validator->validate('0-4X19-92619812', new Isbn()); foreach ($violations as $violation) { var_dump($violation->getCode()); // => int(3) var_dump(Isbn::getErrorName($violation->getCode())); // => string(24) "ERROR_INVALID_CHARACTERS" var_dump($violation->getConstraint()->getErrorName($violation->getCode())); // => string(24) "ERROR_INVALID_CHARACTERS" } ``` The `getErrorName()` method is especially helpful for REST APIs, where you can return both an error code and a description of that error now. **Todos** - [x] Backport a few structural changes to #12016 - [x] Update constraints outside of the Validator component - [x] Rebase on master (after merging #12015 and #12016) Commits ------- 3b50bf2 [Validator] Added error codes to all constraints with multiple error causes
@webmozart I still don't see your argument that the error code can be used in a REST API. The error code is not unique, so if a users reports he received |
@@ -93,11 +93,9 @@ public function setPlural($number); | |||
/** | |||
* Sets the violation code. | |||
* | |||
* @param mixed $code The violation code | |||
* @param int $code The violation code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it makes sense to only change it to int
here when every other code in the validator component is said to be mixed
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw, https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Validator/ConstraintViolation.php#L128 is also not safe to do when code is mixed.
@Tobion Of course you have to provide the name of the failing constraint as well, otherwise the code is useless. We could make sure that the errors are unique by collecting them in a single class instead of within the individual constraints. Do you think that is a better solution? Sketch: namespace Symfony\Component\Validator;
final class Error
{
const FILE_NOT_FOUND = 100;
const FILE_EMPTY = 101;
const IBAN_TOO_SHORT = 200;
private function __construct() { ... }
}
$context->buildViolation('Error!')
->setCode(Error::FILE_NOT_FOUND)
->addViolation();
if (Error::FILE_NOT_FOUND === $violation->getCode()) {
// ...
} |
Well, the name must not really be unique as well. For example there are some as generic as Collecting errors in one place is worse IMO and also would not work with custom constraints anyway. |
I dont see an issue with providing the constraint name along with the error code? It seems much more flexible than collecting the error codes into a single class or trying to ensure they're unique. |
@webmozart thanks for your work on that. Just my two cents: I still sort of prefer something unique-ish like an UUID, but I guess the constraint name + code is enough for me. I don't see the need of dealing with two keys (constraint, code) when the API consumers -which would be my main use case for this feature- can do fine with just a single one (code/uuid). |
@Tobion I understand from your reply that you're not happy with the current solution, but what do you suggest to improve it? |
IMO, the solution depends on the use case. For many cases, the error name is probably a better fit for the REST API than the numeric code. It will also make it easier to understand for people debugging their usage (as the error name can be understood). To make it useful, we just need to make sure that we don't use the same name for things which have actually different meaning (but this is not likely for names). But we don't need to ensure uniqueness. |
👍 This reminds me of an issue I opened on the FosRestBundle repo few weeks ago FriendsOfSymfony/FOSRestBundle#842. I needed an error code (error constant name or error numeric code) for my REST API as I wanted to obtain something like this http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#errors By the way, have you seen this bundle which helps handling errors in REST APIs? https://github.com/TheBigBrainsCompany/TbbcRestUtilBundle/blob/master/README.md |
This would be awesome to have! 👍 |
@lucascourot there are quite a few form related tickets open on the FOSRestBundle that need attention. Since I am personally not using the form component with FOSRestBundle (mostly because a large chunk of the REST related stuff I do is read only APIs) I need helping hands. |
@lsmith77 I think my issue was mainly related to the fact that it wasn't possible to associate an error code to a validation constraint. Unless you extended each constraint class and added an error code attribute. |
@stanlemon This is merged already. The question is: Right now, only those constraints which have multiple error causes have error codes. For example: // caused by NotNull
$violation->getCode();
// => null
// caused by Length
$violation->getCode()
// => 1
Length::getErrorName($violation->getCode());
$violation->getConstraint()->getErrorName($violation->getCode());
// => "TOO_SHORT_ERROR" Also, neither the numeric codes nor the error names are globally unique. So there are many constraints with the error code 1, there are also many constraints with a TOO_SHORT_ERROR. Hence the API output is only useful if you indicate the code/error name together with the name of the constraint causing that error. Now my question: Is this a problem? Or do you prefer globally unique codes so that you know from the code exactly which constraint caused the error and what error it is? We could achieve this by replacing integers by UUIDs. |
@webmozart but TOO_SHORT_ERROR is clear in all cases even if it is used in several places, because it has the same meaing in all cases: the value is too short |
@stof I think you missed to point of the codes. That the value is too short is already clear from the |
@Tobion but for Rest API, most of the time, this code will be enough (while relying on the message itself to identify it is too short is not, given that the message can be updated to fix a typo in the wording for instance) |
Yes "most of the time". But I prefer a system that covers it's intended functionality all the time. |
For reference the follow up change: #15154 |
This PR depends on #12015 and #12016 being merged first. However, a few changes in 52cb7df first must be backported to #12016.
This PR introduces error codes for all constraints with multiple error paths. This lets you determine what exactly the reason was that a constraint failed:
The
getErrorName()
method is especially helpful for REST APIs, where you can return both an error code and a description of that error now.Todos