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

api-platform / core / 15133993414

20 May 2025 09:30AM UTC coverage: 26.313% (-1.2%) from 27.493%
15133993414

Pull #7161

github

web-flow
Merge e2c03d45f into 5459ba375
Pull Request #7161: fix(metadata): infer parameter string type from schema

0 of 2 new or added lines in 1 file covered. (0.0%)

11019 existing lines in 363 files now uncovered.

12898 of 49018 relevant lines covered (26.31%)

34.33 hits per line

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

69.44
/src/Metadata/Resource/Factory/ExtractorResourceMetadataCollectionFactory.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\ApiResource;
17
use ApiPlatform\Metadata\Extractor\ResourceExtractorInterface;
18
use ApiPlatform\Metadata\GraphQl\Operation as GraphQlOperation;
19
use ApiPlatform\Metadata\HttpOperation;
20
use ApiPlatform\Metadata\Operations;
21
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
22
use ApiPlatform\Metadata\Util\CamelCaseToSnakeCaseNameConverter;
23
use Psr\Log\LoggerInterface;
24
use Psr\Log\NullLogger;
25

26
/**
27
 * Creates a resource metadata from {@see Resource} extractors (XML, YAML).
28
 *
29
 * @author Vincent Chalamon <vincentchalamon@gmail.com>
30
 */
31
final class ExtractorResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface
32
{
33
    use OperationDefaultsTrait;
34

35
    public function __construct(private readonly ResourceExtractorInterface $extractor, private readonly ?ResourceMetadataCollectionFactoryInterface $decorated = null, array $defaults = [], ?LoggerInterface $logger = null, private readonly bool $graphQlEnabled = false)
36
    {
UNCOV
37
        $this->logger = $logger ?? new NullLogger();
978✔
UNCOV
38
        $this->defaults = $defaults;
978✔
UNCOV
39
        $this->camelCaseToSnakeCaseNameConverter = new CamelCaseToSnakeCaseNameConverter();
978✔
40
    }
41

42
    /**
43
     * {@inheritdoc}
44
     */
45
    public function create(string $resourceClass): ResourceMetadataCollection
46
    {
UNCOV
47
        $resourceMetadataCollection = new ResourceMetadataCollection($resourceClass);
69✔
UNCOV
48
        if ($this->decorated) {
69✔
UNCOV
49
            $resourceMetadataCollection = $this->decorated->create($resourceClass);
69✔
50
        }
51

UNCOV
52
        if (!(class_exists($resourceClass) || interface_exists($resourceClass)) || !$resources = $this->extractor->getResources()[$resourceClass] ?? false) {
69✔
UNCOV
53
            return $resourceMetadataCollection;
69✔
54
        }
55

UNCOV
56
        foreach ($this->buildResources($resources, $resourceClass) as $resource) {
2✔
UNCOV
57
            foreach ($this->defaults['attributes'] ?? [] as $key => $value) {
2✔
58
                if (method_exists($resource, 'get'.ucfirst($key)) && !$resource->{'get'.ucfirst($key)}()) {
×
59
                    $resource = $resource->{'with'.ucfirst($key)}($value);
×
60
                }
61
            }
62

UNCOV
63
            $resourceMetadataCollection[] = $resource;
2✔
64
        }
65

UNCOV
66
        return $resourceMetadataCollection;
2✔
67
    }
68

69
    /**
70
     * Builds resources to support:.
71
     *
72
     * @return ApiResource[]
73
     */
74
    private function buildResources(array $nodes, string $resourceClass): array
75
    {
UNCOV
76
        $shortName = (false !== $pos = strrpos($resourceClass, '\\')) ? substr($resourceClass, $pos + 1) : $resourceClass;
2✔
UNCOV
77
        $resources = [];
2✔
UNCOV
78
        foreach ($nodes as $node) {
2✔
UNCOV
79
            $resource = (new ApiResource())
2✔
UNCOV
80
                ->withShortName($shortName)
2✔
UNCOV
81
                ->withClass($resourceClass);
2✔
UNCOV
82
            foreach ($node as $key => $value) {
2✔
UNCOV
83
                $methodName = 'with'.ucfirst($key);
2✔
UNCOV
84
                if ('operations' !== $key && null !== $value && method_exists($resource, $methodName)) {
2✔
85
                    $resource = $resource->{$methodName}($value);
1✔
86
                }
87
            }
88

UNCOV
89
            if ($this->graphQlEnabled) {
2✔
UNCOV
90
                $resource = $this->addGraphQlOperations($node['graphQlOperations'] ?? null, $resource);
2✔
91
            }
92

UNCOV
93
            $resources[] = $this->addOperations($node['operations'] ?? null, $resource);
2✔
94
        }
95

UNCOV
96
        return $resources;
2✔
97
    }
98

99
    private function addOperations(?array $data, ApiResource $resource): ApiResource
100
    {
UNCOV
101
        $operations = [];
2✔
102

UNCOV
103
        if (null === $data) {
2✔
104
            foreach ($this->getDefaultHttpOperations($resource) as $operation) {
1✔
105
                [$key, $operation] = $this->getOperationWithDefaults($resource, $operation);
1✔
106
                $operations[$key] = $operation;
1✔
107
            }
108

109
            return $resource->withOperations(new Operations($operations));
1✔
110
        }
111

UNCOV
112
        foreach ($data as $attributes) {
2✔
UNCOV
113
            if (!class_exists($attributes['class'])) {
2✔
114
                throw new \InvalidArgumentException(\sprintf('Operation "%s" does not exist.', $attributes['class']));
×
115
            }
116

117
            /** @var HttpOperation $operation */
UNCOV
118
            $operation = (new $attributes['class']())->withShortName($resource->getShortName());
2✔
UNCOV
119
            unset($attributes['class']);
2✔
UNCOV
120
            foreach ($attributes as $key => $value) {
2✔
UNCOV
121
                if (null === $value) {
2✔
UNCOV
122
                    continue;
2✔
123
                }
124

125
                $camelCaseKey = $this->camelCaseToSnakeCaseNameConverter->denormalize($key);
1✔
126
                $methodName = 'with'.ucfirst($camelCaseKey);
1✔
127

128
                if (method_exists($operation, $methodName)) {
1✔
129
                    $operation = $operation->{$methodName}($value);
1✔
130
                    continue;
1✔
131
                }
132

133
                $operation = $operation->withExtraProperties(array_merge($operation->getExtraProperties(), [$key => $value]));
×
134
            }
135

UNCOV
136
            [$key, $operation] = $this->getOperationWithDefaults($resource, $operation);
2✔
UNCOV
137
            $operations[$key] = $operation;
2✔
138
        }
139

UNCOV
140
        return $resource->withOperations(new Operations($operations));
2✔
141
    }
142

143
    private function addGraphQlOperations(?array $data, ApiResource $resource): ApiResource
144
    {
UNCOV
145
        $operations = [];
2✔
146

UNCOV
147
        if (null === $data) {
2✔
UNCOV
148
            return $this->addDefaultGraphQlOperations($resource);
2✔
149
        }
150

151
        foreach ($data as $attributes) {
×
152
            if (!class_exists($attributes['class'])) {
×
153
                throw new \InvalidArgumentException(\sprintf('Operation "%s" does not exist.', $attributes['class']));
×
154
            }
155

156
            /** @var GraphQlOperation $operation */
157
            $operation = (new $attributes['class']())->withShortName($resource->getShortName());
×
158
            unset($attributes['class']);
×
159
            foreach ($attributes as $key => $value) {
×
160
                if (null === $value) {
×
161
                    continue;
×
162
                }
163

164
                $camelCaseKey = $this->camelCaseToSnakeCaseNameConverter->denormalize($key);
×
165
                $methodName = 'with'.ucfirst($camelCaseKey);
×
166

167
                if (method_exists($operation, $methodName)) {
×
168
                    $operation = $operation->{$methodName}($value);
×
169
                    continue;
×
170
                }
171

172
                $operation = $operation->withExtraProperties(array_merge($operation->getExtraProperties(), [$key => $value]));
×
173
            }
174

175
            [$key, $operation] = $this->getOperationWithDefaults($resource, $operation);
×
176
            $operations[$key] = $operation;
×
177
        }
178

179
        $resource = $resource->withGraphQlOperations($operations);
×
180

181
        return $this->completeGraphQlOperations($resource);
×
182
    }
183
}
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

© 2025 Coveralls, Inc