Passed
Push — 2.5 ( f50b5e...b47cce )
by Kévin
04:21
created

IdentifierConverter::getIdentifierType()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 3
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
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\Identifier;
15
16
use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
17
use ApiPlatform\Core\Exception\InvalidIdentifierException;
18
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
19
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
20
use Symfony\Component\PropertyInfo\Type;
21
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
22
23
/**
24
 * Identifier converter that chains identifier denormalizers.
25
 *
26
 * @author Antoine Bluchet <[email protected]>
27
 */
28
final class IdentifierConverter implements ContextAwareIdentifierConverterInterface
29
{
30
    private $propertyMetadataFactory;
31
    private $identifiersExtractor;
32
    private $identifierDenormalizers;
33
    private $resourceMetadataFactory;
34
35
    /**
36
     * @param iterable<DenormalizerInterface> $identifierDenormalizers
37
     */
38
    public function __construct(IdentifiersExtractorInterface $identifiersExtractor, PropertyMetadataFactoryInterface $propertyMetadataFactory, iterable $identifierDenormalizers, ResourceMetadataFactoryInterface $resourceMetadataFactory = null)
39
    {
40
        $this->propertyMetadataFactory = $propertyMetadataFactory;
41
        $this->identifiersExtractor = $identifiersExtractor;
42
        $this->identifierDenormalizers = $identifierDenormalizers;
43
        $this->resourceMetadataFactory = $resourceMetadataFactory;
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49
    public function convert(string $data, string $class, array $context = []): array
50
    {
51
        if (null !== $this->resourceMetadataFactory) {
52
            $resourceMetadata = $this->resourceMetadataFactory->create($class);
53
            $class = $resourceMetadata->getOperationAttribute($context, 'output', ['class' => $class], true)['class'];
54
        }
55
56
        $keys = $this->identifiersExtractor->getIdentifiersFromResourceClass($class);
57
58
        if (($numIdentifiers = \count($keys)) > 1) {
59
            $identifiers = CompositeIdentifierParser::parse($data);
60
        } elseif (0 === $numIdentifiers) {
61
            throw new InvalidIdentifierException(sprintf('Resource "%s" has no identifiers.', $class));
62
        } else {
63
            $identifiers = [$keys[0] => $data];
64
        }
65
66
        // Normalize every identifier (DateTime, UUID etc.)
67
        foreach ($keys as $key) {
68
            if (!isset($identifiers[$key])) {
69
                throw new InvalidIdentifierException(sprintf('Invalid identifier "%1$s", "%1$s" was not found.', $key));
70
            }
71
72
            if (null === $type = $this->getIdentifierType($class, $key)) {
73
                continue;
74
            }
75
76
            foreach ($this->identifierDenormalizers as $identifierDenormalizer) {
77
                if (!$identifierDenormalizer->supportsDenormalization($identifiers[$key], $type)) {
78
                    continue;
79
                }
80
81
                try {
82
                    $identifiers[$key] = $identifierDenormalizer->denormalize($identifiers[$key], $type);
83
                } catch (InvalidIdentifierException $e) {
84
                    throw new InvalidIdentifierException(sprintf('Identifier "%s" could not be denormalized.', $key), $e->getCode(), $e);
85
                }
86
            }
87
        }
88
89
        return $identifiers;
90
    }
91
92
    private function getIdentifierType(string $resourceClass, string $property): ?string
93
    {
94
        if (!$type = $this->propertyMetadataFactory->create($resourceClass, $property)->getType()) {
95
            return null;
96
        }
97
98
        return Type::BUILTIN_TYPE_OBJECT === ($builtinType = $type->getBuiltinType()) ? $type->getClassName() : $builtinType;
99
    }
100
}
101