• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 10729306835

05 Sep 2024 10:46PM UTC coverage: 7.655% (-0.01%) from 7.665%
10729306835

push

github

web-flow
Merge pull request #6586 from soyuka/merge-342

Merge 3.4

0 of 54 new or added lines in 12 files covered. (0.0%)

8760 existing lines in 277 files now uncovered.

12505 of 163357 relevant lines covered (7.66%)

22.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.83
/src/Metadata/Resource/Factory/LinkFactory.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
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\Metadata\Resource\Factory;
15

16
use ApiPlatform\Metadata\Exception\RuntimeException;
17
use ApiPlatform\Metadata\Link;
18
use ApiPlatform\Metadata\Metadata;
19
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
20
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
21
use ApiPlatform\Metadata\ResourceClassResolverInterface;
22
use Symfony\Component\PropertyInfo\Type;
23

24
/**
25
 * @internal
26
 */
27
final class LinkFactory implements LinkFactoryInterface, PropertyLinkFactoryInterface
28
{
29
    public function __construct(private readonly PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, private readonly PropertyMetadataFactoryInterface $propertyMetadataFactory, private readonly ResourceClassResolverInterface $resourceClassResolver)
30
    {
UNCOV
31
    }
2,248✔
32

33
    /**
34
     * {@inheritdoc}
35
     */
36
    public function createLinkFromProperty(Metadata $operation, string $property): Link
37
    {
38
        $metadata = $this->propertyMetadataFactory->create($resourceClass = $operation->getClass(), $property);
1✔
39
        $relationClass = $this->getPropertyClassType($metadata->getBuiltinTypes());
1✔
40
        if (!$relationClass) {
1✔
41
            throw new RuntimeException(\sprintf('We could not find a class matching the uriVariable "%s" on "%s".', $property, $resourceClass));
×
42
        }
43

44
        $identifiers = $this->resourceClassResolver->isResourceClass($relationClass) ? $this->getIdentifiersFromResourceClass($relationClass) : ['id'];
1✔
45

46
        return new Link(fromClass: $relationClass, toProperty: $property, identifiers: $identifiers, parameterName: $property);
1✔
47
    }
48

49
    /**
50
     * {@inheritdoc}
51
     */
52
    public function createLinksFromIdentifiers(Metadata $operation): array
53
    {
UNCOV
54
        $identifiers = $this->getIdentifiersFromResourceClass($resourceClass = $operation->getClass());
33✔
55

UNCOV
56
        if (!$identifiers) {
33✔
UNCOV
57
            return [];
5✔
58
        }
59

UNCOV
60
        $link = (new Link())->withFromClass($resourceClass)->withIdentifiers($identifiers);
32✔
UNCOV
61
        $parameterName = $identifiers[0];
32✔
UNCOV
62
        if ('value' === $parameterName && enum_exists($resourceClass)) {
32✔
UNCOV
63
            $parameterName = 'id';
3✔
64
        }
65

UNCOV
66
        if (1 < \count($identifiers)) {
32✔
UNCOV
67
            $parameterName = 'id';
5✔
UNCOV
68
            $link = $link->withCompositeIdentifier(true);
5✔
69
        }
70

UNCOV
71
        return [$link->withParameterName($parameterName)];
32✔
72
    }
73

74
    /**
75
     * {@inheritdoc}
76
     */
77
    public function createLinksFromRelations(Metadata $operation): array
78
    {
UNCOV
79
        $links = [];
31✔
UNCOV
80
        foreach ($this->propertyNameCollectionFactory->create($resourceClass = $operation->getClass()) as $property) {
31✔
UNCOV
81
            $metadata = $this->propertyMetadataFactory->create($resourceClass, $property);
31✔
82

UNCOV
83
            if (!($relationClass = $this->getPropertyClassType($metadata->getBuiltinTypes())) || !$this->resourceClassResolver->isResourceClass($relationClass)) {
31✔
UNCOV
84
                continue;
31✔
85
            }
86

UNCOV
87
            $identifiers = $this->getIdentifiersFromResourceClass($resourceClass);
16✔
88

UNCOV
89
            $links[] = (new Link())->withFromProperty($property)->withFromClass($resourceClass)->withToClass($relationClass)->withIdentifiers($identifiers);
16✔
90
        }
91

UNCOV
92
        return $links;
31✔
93
    }
94

95
    /**
96
     * {@inheritdoc}
97
     */
98
    public function createLinksFromAttributes(Metadata $operation): array
99
    {
UNCOV
100
        $links = [];
31✔
101
        try {
UNCOV
102
            $reflectionClass = new \ReflectionClass($resourceClass = $operation->getClass());
31✔
UNCOV
103
            foreach ($this->propertyNameCollectionFactory->create($resourceClass) as $property) {
31✔
UNCOV
104
                $reflectionProperty = $reflectionClass->getProperty($property);
31✔
105

UNCOV
106
                foreach ($reflectionProperty->getAttributes(Link::class) as $attributeLink) {
31✔
UNCOV
107
                    $metadata = $this->propertyMetadataFactory->create($resourceClass, $property);
3✔
108

UNCOV
109
                    $attributeLink = $attributeLink->newInstance()
3✔
UNCOV
110
                        ->withFromProperty($property);
3✔
111

UNCOV
112
                    if (!$attributeLink->getFromClass()) {
3✔
UNCOV
113
                        $attributeLink = $attributeLink->withFromClass($resourceClass)->withToClass($this->getPropertyClassType($metadata->getBuiltinTypes()) ?? $resourceClass);
3✔
114
                    }
115

UNCOV
116
                    $links[] = $attributeLink;
3✔
117
                }
118
            }
UNCOV
119
        } catch (\ReflectionException) {
8✔
120
        }
121

UNCOV
122
        return $links;
31✔
123
    }
124

125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function completeLink(Link $link): Link
129
    {
UNCOV
130
        if (!$link->getIdentifiers()) {
18✔
UNCOV
131
            $link = $link->withIdentifiers($this->getIdentifiersFromResourceClass($link->getFromClass()));
15✔
132
        }
133

UNCOV
134
        if (1 < \count((array) $link->getIdentifiers())) {
18✔
135
            $link = $link->withCompositeIdentifier(true);
×
136
        }
137

UNCOV
138
        return $link;
18✔
139
    }
140

141
    private function getIdentifiersFromResourceClass(string $resourceClass): array
142
    {
UNCOV
143
        $hasIdProperty = false;
33✔
UNCOV
144
        $identifiers = [];
33✔
UNCOV
145
        foreach ($this->propertyNameCollectionFactory->create($resourceClass) as $property) {
33✔
UNCOV
146
            $isIdentifier = $this->propertyMetadataFactory->create($resourceClass, $property)->isIdentifier();
33✔
147

UNCOV
148
            if (!$hasIdProperty && null === $isIdentifier) {
33✔
UNCOV
149
                $hasIdProperty = 'id' === $property;
33✔
150
            }
151

UNCOV
152
            if ($isIdentifier) {
33✔
UNCOV
153
                $identifiers[] = $property;
30✔
154
            }
155
        }
156

UNCOV
157
        if ($hasIdProperty && !$identifiers) {
33✔
UNCOV
158
            return ['id'];
4✔
159
        }
160

UNCOV
161
        if (!$hasIdProperty && !$identifiers && enum_exists($resourceClass)) {
31✔
UNCOV
162
            return ['value'];
3✔
163
        }
164

UNCOV
165
        return $identifiers;
31✔
166
    }
167

168
    /**
169
     * @param Type[]|null $types
170
     */
171
    private function getPropertyClassType(?array $types): ?string
172
    {
UNCOV
173
        foreach ($types ?? [] as $type) {
31✔
UNCOV
174
            if ($type->isCollection()) {
31✔
UNCOV
175
                return $this->getPropertyClassType($type->getCollectionValueTypes());
14✔
176
            }
177

UNCOV
178
            if ($class = $type->getClassName()) {
31✔
UNCOV
179
                return $class;
22✔
180
            }
181
        }
182

UNCOV
183
        return null;
31✔
184
    }
185
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc