bug #27292 [Serializer] Fix and improve constraintViolationListNormalizer's RFC7807 compliance (dunglas)

This PR was squashed before being merged into the 4.1 branch (closes #27292).

Discussion
----------

[Serializer] Fix and improve constraintViolationListNormalizer's RFC7807 compliance

| Q             | A
| ------------- | ---
| Branch?       | 4.1
| Bug fix?      | yes
| New feature?  | no <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | yes| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | https://github.com/symfony/symfony/pull/22150#discussion_r188674031
| License       | MIT
| Doc PR        | todo

This PR fixes and improves [RFC 7807](https://tools.ietf.org/html/rfc7807#section-3.2) compliance of `ConstraintViolationListNormalizer` (introduced in 4.1):

* As recommended, use a specific namespace for Symfony validation error (`http://symfony.com/doc/current/validation.html`, because it already exists and gives information about the error.
* Allow to set all properties defined in the RFC using the serialization context
* Remove the `detail` key if no detail is provided (according to the spec)
* Change the Symfony specific extension to use the same terminology than the RFC itself (type and title)
* Use the proper `urn:uuid` scheme (RFC 4122) for the UUID code (more standard, and improve hypermedia capabilities).

ping @teohhanhui

Commits
-------

3c789c610a [Serializer] Fix and improve constraintViolationListNormalizer's RFC7807 compliance
This commit is contained in:
Fabien Potencier 2018-05-21 17:32:37 +02:00
commit 7fb7cf26ad
2 changed files with 31 additions and 14 deletions

View File

@ -32,21 +32,37 @@ class ConstraintViolationListNormalizer implements NormalizerInterface, Cacheabl
$violations = array();
$messages = array();
foreach ($object as $violation) {
$violations[] = array(
'propertyPath' => $violation->getPropertyPath(),
'message' => $violation->getMessage(),
'code' => $violation->getCode(),
);
$propertyPath = $violation->getPropertyPath();
$violationEntry = array(
'propertyPath' => $propertyPath,
'title' => $violation->getMessage(),
);
if (null !== $code = $violation->getCode()) {
$violationEntry['type'] = sprintf('urn:uuid:%s', $code);
}
$violations[] = $violationEntry;
$prefix = $propertyPath ? sprintf('%s: ', $propertyPath) : '';
$messages[] = $prefix.$violation->getMessage();
}
return array(
'title' => isset($context['title']) ? $context['title'] : 'An error occurred',
'detail' => $messages ? implode("\n", $messages) : '',
'violations' => $violations,
$result = array(
'type' => $context['type'] ?? 'https://symfony.com/errors/validation',
'title' => $context['title'] ?? 'Validation Failed',
);
if (isset($context['status'])) {
$result['status'] = $context['status'];
}
if ($messages) {
$result['detail'] = implode("\n", $messages);
}
if (isset($context['instance'])) {
$result['instance'] = $context['instance'];
}
return $result + array('violations' => $violations);
}
/**

View File

@ -43,19 +43,20 @@ class ConstraintViolationListNormalizerTest extends TestCase
));
$expected = array(
'title' => 'An error occurred',
'type' => 'https://symfony.com/errors/validation',
'title' => 'Validation Failed',
'detail' => 'd: a
4: 1',
'violations' => array(
array(
'propertyPath' => 'd',
'message' => 'a',
'code' => 'f',
'title' => 'a',
'type' => 'urn:uuid:f',
),
array(
'propertyPath' => '4',
'message' => '1',
'code' => '6',
'title' => '1',
'type' => 'urn:uuid:6',
),
),
);