Passed
Push — master ( 8bd912...d93388 )
by Alan
06:58 queued 02:20
created

Serializer/ConstraintViolationListNormalizer.php (1 issue)

1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace ApiPlatform\Core\JsonApi\Serializer;
15
16
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
17
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
18
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
19
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
20
use Symfony\Component\Validator\ConstraintViolationInterface;
21
use Symfony\Component\Validator\ConstraintViolationListInterface;
22
23
/**
24
 * Converts {@see \Symfony\Component\Validator\ConstraintViolationListInterface} to a JSON API error representation.
25
 *
26
 * @author Héctor Hurtarte <[email protected]>
27
 */
28
final class ConstraintViolationListNormalizer implements NormalizerInterface, CacheableSupportsMethodInterface
29
{
30
    public const FORMAT = 'jsonapi';
31
32
    private $nameConverter;
33
    private $propertyMetadataFactory;
34
35
    public function __construct(PropertyMetadataFactoryInterface $propertyMetadataFactory, NameConverterInterface $nameConverter = null)
36
    {
37
        $this->propertyMetadataFactory = $propertyMetadataFactory;
38
        $this->nameConverter = $nameConverter;
39
    }
40
41
    public function normalize($object, $format = null, array $context = [])
42
    {
43
        $violations = [];
44
        foreach ($object as $violation) {
45
            $violations[] = [
46
                'detail' => $violation->getMessage(),
47
                'source' => [
48
                    'pointer' => $this->getSourcePointerFromViolation($violation),
49
                ],
50
            ];
51
        }
52
53
        return ['errors' => $violations];
54
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59
    public function supportsNormalization($data, $format = null)
60
    {
61
        return self::FORMAT === $format && $data instanceof ConstraintViolationListInterface;
62
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67
    public function hasCacheableSupportsMethod(): bool
68
    {
69
        return true;
70
    }
71
72
    private function getSourcePointerFromViolation(ConstraintViolationInterface $violation)
73
    {
74
        $fieldName = $violation->getPropertyPath();
75
76
        if (!$fieldName) {
77
            return 'data';
78
        }
79
80
        $class = \get_class($violation->getRoot());
81
        $propertyMetadata = $this->propertyMetadataFactory
82
            ->create(
83
                // Im quite sure this requires some thought in case of validations over relationships
84
                $class,
85
                $fieldName
86
            );
87
88
        if (null !== $this->nameConverter) {
89
            $fieldName = $this->nameConverter->normalize($fieldName, $class, self::FORMAT);
0 ignored issues
show
The call to Symfony\Component\Serial...rInterface::normalize() has too many arguments starting with $class. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

89
            /** @scrutinizer ignore-call */ 
90
            $fieldName = $this->nameConverter->normalize($fieldName, $class, self::FORMAT);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
90
        }
91
92
        if (($type = $propertyMetadata->getType()) && null !== $type->getClassName()) {
93
            return "data/relationships/$fieldName";
94
        }
95
96
        return "data/attributes/$fieldName";
97
    }
98
}
99