• 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

89.66
/src/Metadata/Property/Factory/ExtractorPropertyMetadataFactory.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\Property\Factory;
15

16
use ApiPlatform\JsonSchema\Metadata\Property\Factory\SchemaPropertyMetadataFactory;
17
use ApiPlatform\Metadata\ApiProperty;
18
use ApiPlatform\Metadata\Exception\PropertyNotFoundException;
19
use ApiPlatform\Metadata\Extractor\PropertyExtractorInterface;
20
use Symfony\Component\PropertyInfo\Type;
21

22
/**
23
 * Creates properties's metadata using an extractor.
24
 *
25
 * @author Kévin Dunglas <dunglas@gmail.com>
26
 * @author Vincent Chalamon <vincentchalamon@gmail.com>
27
 */
28
final class ExtractorPropertyMetadataFactory implements PropertyMetadataFactoryInterface
29
{
30
    public function __construct(private readonly PropertyExtractorInterface $extractor, private readonly ?PropertyMetadataFactoryInterface $decorated = null)
31
    {
UNCOV
32
    }
979✔
33

34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function create(string $resourceClass, string $property, array $options = []): ApiProperty
38
    {
UNCOV
39
        $parentPropertyMetadata = null;
240✔
UNCOV
40
        if ($this->decorated) {
240✔
41
            try {
UNCOV
42
                $parentPropertyMetadata = $this->decorated->create($resourceClass, $property, $options);
240✔
43
            } catch (PropertyNotFoundException) {
×
44
                // Ignore not found exception from decorated factories
45
            }
46
        }
47

48
        if (
UNCOV
49
            !property_exists($resourceClass, $property) && !interface_exists($resourceClass)
240✔
UNCOV
50
            || null === ($propertyMetadata = $this->extractor->getProperties()[$resourceClass][$property] ?? null)
240✔
51
        ) {
UNCOV
52
            return $this->handleNotFound($parentPropertyMetadata, $resourceClass, $property);
240✔
53
        }
54

UNCOV
55
        if ($parentPropertyMetadata) {
9✔
UNCOV
56
            return $this->handleUserDefinedSchema($this->update($parentPropertyMetadata, $propertyMetadata));
8✔
57
        }
58

59
        $apiProperty = new ApiProperty();
4✔
60

61
        foreach ($propertyMetadata as $key => $value) {
4✔
62
            if ('builtinTypes' === $key && null !== $value) {
4✔
63
                $value = array_map(fn (string $builtinType): Type => new Type($builtinType), $value);
4✔
64
            }
65

66
            $methodName = 'with'.ucfirst($key);
4✔
67

68
            if (method_exists($apiProperty, $methodName) && null !== $value) {
4✔
69
                $apiProperty = $apiProperty->{$methodName}($value);
4✔
70
            }
71
        }
72

73
        return $this->handleUserDefinedSchema($apiProperty);
4✔
74
    }
75

76
    /**
77
     * Returns the metadata from the decorated factory if available or throws an exception.
78
     *
79
     * @throws PropertyNotFoundException
80
     */
81
    private function handleNotFound(?ApiProperty $parentPropertyMetadata, string $resourceClass, string $property): ApiProperty
82
    {
UNCOV
83
        if ($parentPropertyMetadata) {
240✔
UNCOV
84
            return $parentPropertyMetadata;
240✔
85
        }
86

UNCOV
87
        throw new PropertyNotFoundException(\sprintf('Property "%s" of the resource class "%s" not found.', $property, $resourceClass));
239✔
88
    }
89

90
    /**
91
     * Creates a new instance of metadata if the property is not already set.
92
     */
93
    private function update(ApiProperty $propertyMetadata, array $metadata): ApiProperty
94
    {
UNCOV
95
        foreach (get_class_methods(ApiProperty::class) as $method) {
8✔
UNCOV
96
            if (preg_match('/^(?:get|is)(.*)/', (string) $method, $matches) && null !== ($val = $metadata[lcfirst($matches[1])] ?? null) && method_exists($propertyMetadata, "with{$matches[1]}")) {
8✔
UNCOV
97
                $propertyMetadata = $propertyMetadata->{"with{$matches[1]}"}($val);
8✔
98
            }
99
        }
100

UNCOV
101
        return $propertyMetadata;
8✔
102
    }
103

104
    private function handleUserDefinedSchema(ApiProperty $propertyMetadata): ApiProperty
105
    {
106
        // can't know later if the schema has been defined by the user or by API Platform
107
        // store extra key to make this difference
UNCOV
108
        if (null !== $propertyMetadata->getSchema()) {
9✔
109
            $extraProperties = $propertyMetadata->getExtraProperties() ?? [];
×
110
            $propertyMetadata = $propertyMetadata->withExtraProperties([SchemaPropertyMetadataFactory::JSON_SCHEMA_USER_DEFINED => true] + $extraProperties);
×
111
        }
112

UNCOV
113
        return $propertyMetadata;
9✔
114
    }
115
}
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