Completed
Push — master ( c01aea...f73309 )
by Antoine
12s
created

IdentifiersExtractor::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 3
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the API Platform project.
7
 *
8
 * (c) Kévin Dunglas <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace ApiPlatform\Core\Api;
15
16
use ApiPlatform\Core\Exception\RuntimeException;
17
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
18
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
19
use ApiPlatform\Core\Util\ClassInfoTrait;
20
use Symfony\Component\PropertyAccess\PropertyAccess;
21
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
22
23
/**
24
 * {@inheritdoc}
25
 *
26
 * @author Antoine Bluchet <[email protected]>
27
 */
28
final class IdentifiersExtractor implements IdentifiersExtractorInterface
29
{
30
    use ClassInfoTrait;
31
32
    private $propertyNameCollectionFactory;
33
    private $propertyMetadataFactory;
34
    private $propertyAccessor;
35
36
    public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, PropertyAccessorInterface $propertyAccessor = null)
37
    {
38
        $this->propertyNameCollectionFactory = $propertyNameCollectionFactory;
39
        $this->propertyMetadataFactory = $propertyMetadataFactory;
40
        $this->propertyAccessor = $propertyAccessor ?? PropertyAccess::createPropertyAccessor();
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function getIdentifiersFromItem($item): array
47
    {
48
        $identifiers = [];
49
        $resourceClass = $this->getObjectClass($item);
50
51
        foreach ($this->propertyNameCollectionFactory->create($resourceClass) as $propertyName) {
52
            $propertyMetadata = $this->propertyMetadataFactory->create($resourceClass, $propertyName);
53
54
            $identifier = $propertyMetadata->isIdentifier();
55
            if (null === $identifier || false === $identifier) {
56
                continue;
57
            }
58
59
            $identifiers[$propertyName] = $this->propertyAccessor->getValue($item, $propertyName);
60
61
            if (!is_object($identifiers[$propertyName])) {
62
                continue;
63
            }
64
65
            $relatedResourceClass = $this->getObjectClass($identifiers[$propertyName]);
66
            $relatedItem = $identifiers[$propertyName];
67
68
            unset($identifiers[$propertyName]);
69
70
            foreach ($this->propertyNameCollectionFactory->create($relatedResourceClass) as $relatedPropertyName) {
71
                $propertyMetadata = $this->propertyMetadataFactory->create($relatedResourceClass, $relatedPropertyName);
72
73
                if ($propertyMetadata->isIdentifier()) {
74
                    if (isset($identifiers[$propertyName])) {
75
                        throw new RuntimeException(sprintf('Composite identifiers not supported in "%s" through relation "%s" of "%s" used as identifier', $relatedResourceClass, $propertyName, $resourceClass));
76
                    }
77
78
                    $identifiers[$propertyName] = $this->propertyAccessor->getValue($relatedItem, $relatedPropertyName);
79
                }
80
            }
81
82
            if (!isset($identifiers[$propertyName])) {
83
                throw new RuntimeException(sprintf('No identifier found in "%s" through relation "%s" of "%s" used as identifier', $relatedResourceClass, $propertyName, $resourceClass));
84
            }
85
        }
86
87
        return $identifiers;
88
    }
89
}
90