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

api-platform / core / 16531587208

25 Jul 2025 09:05PM UTC coverage: 0.0% (-22.1%) from 22.07%
16531587208

Pull #7225

github

web-flow
Merge 23f449a58 into 02a764950
Pull Request #7225: feat: json streamer

0 of 294 new or added lines in 31 files covered. (0.0%)

11514 existing lines in 375 files now uncovered.

0 of 51976 relevant lines covered (0.0%)

0.0 hits per line

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

0.0
/src/OpenApi/Factory/TypeFactoryTrait.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\OpenApi\Factory;
15

16
use Ramsey\Uuid\UuidInterface;
17
use Symfony\Component\PropertyInfo\Type as LegacyType;
18
use Symfony\Component\TypeInfo\Type as NativeType;
19
use Symfony\Component\TypeInfo\Type\CollectionType;
20
use Symfony\Component\TypeInfo\Type\ObjectType;
21
use Symfony\Component\TypeInfo\TypeIdentifier;
22
use Symfony\Component\Uid\Ulid;
23
use Symfony\Component\Uid\Uuid;
24

25
/**
26
 * @internal
27
 */
28
trait TypeFactoryTrait
29
{
30
    /**
31
     * @return array<string, mixed>
32
     */
33
    private function getType(LegacyType|NativeType $type): array
34
    {
UNCOV
35
        if ($type instanceof NativeType) {
×
UNCOV
36
            return $this->getNativeType($type);
×
37
        }
38

39
        if ($type->isCollection()) {
×
40
            $keyType = $type->getCollectionKeyTypes()[0] ?? null;
×
41
            $subType = ($type->getCollectionValueTypes()[0] ?? null) ?? new LegacyType($type->getBuiltinType(), false, $type->getClassName(), false);
×
42

43
            if (null !== $keyType && LegacyType::BUILTIN_TYPE_STRING === $keyType->getBuiltinType()) {
×
44
                return $this->addNullabilityToTypeDefinition([
×
45
                    'type' => 'object',
×
46
                    'additionalProperties' => $this->getType($subType),
×
47
                ], $type);
×
48
            }
49

50
            return $this->addNullabilityToTypeDefinition([
×
51
                'type' => 'array',
×
52
                'items' => $this->getType($subType),
×
53
            ], $type);
×
54
        }
55

56
        return $this->addNullabilityToTypeDefinition($this->makeLegacyBasicType($type), $type);
×
57
    }
58

59
    /**
60
     * @return array<string, mixed>
61
     */
62
    private function getNativeType(NativeType $type): array
63
    {
UNCOV
64
        if ($type instanceof CollectionType) {
×
UNCOV
65
            $keyType = $type->getCollectionKeyType();
×
UNCOV
66
            $subType = $type->getCollectionValueType();
×
67

UNCOV
68
            if ($keyType->isIdentifiedBy(TypeIdentifier::STRING)) {
×
69
                return $this->addNullabilityToTypeDefinition([
×
70
                    'type' => 'object',
×
71
                    'additionalProperties' => $this->getNativeType($subType),
×
72
                ], $type);
×
73
            }
74

UNCOV
75
            return $this->addNullabilityToTypeDefinition([
×
UNCOV
76
                'type' => 'array',
×
UNCOV
77
                'items' => $this->getNativeType($subType),
×
UNCOV
78
            ], $type);
×
79
        }
80

UNCOV
81
        return $this->addNullabilityToTypeDefinition($this->makeBasicType($type), $type);
×
82
    }
83

84
    /**
85
     * @return array<string, mixed>
86
     */
87
    private function makeLegacyBasicType(LegacyType $type): array
88
    {
89
        return match ($type->getBuiltinType()) {
×
90
            LegacyType::BUILTIN_TYPE_INT => ['type' => 'integer'],
×
91
            LegacyType::BUILTIN_TYPE_FLOAT => ['type' => 'number'],
×
92
            LegacyType::BUILTIN_TYPE_BOOL => ['type' => 'boolean'],
×
93
            LegacyType::BUILTIN_TYPE_OBJECT => $this->getClassType($type->getClassName(), $type->isNullable()),
×
94
            default => ['type' => 'string'],
×
95
        };
×
96
    }
97

98
    /**
99
     * @return array<string, mixed>
100
     */
101
    private function makeBasicType(NativeType $type): array
102
    {
UNCOV
103
        if ($type->isIdentifiedBy(TypeIdentifier::INT)) {
×
UNCOV
104
            return ['type' => 'integer'];
×
105
        }
UNCOV
106
        if ($type->isIdentifiedBy(TypeIdentifier::FLOAT)) {
×
UNCOV
107
            return ['type' => 'number'];
×
108
        }
UNCOV
109
        if ($type->isIdentifiedBy(TypeIdentifier::BOOL)) {
×
UNCOV
110
            return ['type' => 'boolean'];
×
111
        }
UNCOV
112
        if ($type instanceof ObjectType) {
×
113
            return $this->getClassType($type->getClassName(), $type->isNullable());
×
114
        }
115

116
        // Default for other built-in types like string, resource, mixed, etc.
UNCOV
117
        return ['type' => 'string'];
×
118
    }
119

120
    /**
121
     * Gets the JSON Schema document which specifies the data type corresponding to the given PHP class, and recursively adds needed new schema to the current schema if provided.
122
     *
123
     * @return array<string, mixed>
124
     */
125
    private function getClassType(?string $className, bool $nullable): array
126
    {
127
        if (null === $className) {
×
128
            return ['type' => 'string'];
×
129
        }
130

131
        if (is_a($className, \DateTimeInterface::class, true)) {
×
132
            return [
×
133
                'type' => 'string',
×
134
                'format' => 'date-time',
×
135
            ];
×
136
        }
137
        if (is_a($className, \DateInterval::class, true)) {
×
138
            return [
×
139
                'type' => 'string',
×
140
                'format' => 'duration',
×
141
            ];
×
142
        }
143
        if (is_a($className, UuidInterface::class, true) || is_a($className, Uuid::class, true)) {
×
144
            return [
×
145
                'type' => 'string',
×
146
                'format' => 'uuid',
×
147
            ];
×
148
        }
149
        if (is_a($className, Ulid::class, true)) {
×
150
            return [
×
151
                'type' => 'string',
×
152
                'format' => 'ulid',
×
153
            ];
×
154
        }
155
        if (is_a($className, \SplFileInfo::class, true)) {
×
156
            return [
×
157
                'type' => 'string',
×
158
                'format' => 'binary',
×
159
            ];
×
160
        }
161

162
        if (is_a($className, \BackedEnum::class, true)) {
×
163
            $enumCases = array_map(static fn (\BackedEnum $enum): string|int => $enum->value, $className::cases());
×
164

165
            $type = \is_string($enumCases[0] ?? '') ? 'string' : 'integer';
×
166

167
            if ($nullable) {
×
168
                $enumCases[] = null;
×
169
            }
170

171
            return [
×
172
                'type' => $type,
×
173
                'enum' => $enumCases,
×
174
            ];
×
175
        }
176

177
        return ['type' => 'string'];
×
178
    }
179

180
    /**
181
     * @param array<string, mixed> $jsonSchema
182
     *
183
     * @return array<string, mixed>
184
     */
185
    private function addNullabilityToTypeDefinition(array $jsonSchema, LegacyType|NativeType $type): array
186
    {
UNCOV
187
        if (!$type->isNullable()) {
×
UNCOV
188
            return $jsonSchema;
×
189
        }
190

191
        $typeDefinition = ['anyOf' => [$jsonSchema]];
×
192
        $typeDefinition['anyOf'][] = ['type' => 'null'];
×
193

194
        return $typeDefinition;
×
195
    }
196
}
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