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

api-platform / core / 14635100171

24 Apr 2025 06:39AM UTC coverage: 8.271% (+0.02%) from 8.252%
14635100171

Pull #6904

github

web-flow
Merge c9cefd82e into a3e5e53ea
Pull Request #6904: feat(graphql): added support for graphql subscriptions to work for actions

0 of 73 new or added lines in 3 files covered. (0.0%)

1999 existing lines in 144 files now uncovered.

13129 of 158728 relevant lines covered (8.27%)

13.6 hits per line

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

48.96
/src/Doctrine/Odm/PropertyInfo/DoctrineExtractor.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\Doctrine\Odm\PropertyInfo;
15

16
use Doctrine\Common\Collections\Collection;
17
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata as MongoDbClassMetadata;
18
use Doctrine\ODM\MongoDB\Types\Type as MongoDbType;
19
use Doctrine\Persistence\Mapping\ClassMetadata;
20
use Doctrine\Persistence\Mapping\MappingException;
21
use Doctrine\Persistence\ObjectManager;
22
use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
23
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
24
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
25
use Symfony\Component\PropertyInfo\Type as LegacyType;
26
use Symfony\Component\TypeInfo\Type;
27
use Symfony\Component\TypeInfo\TypeIdentifier;
28

29
/**
30
 * Extracts data using Doctrine MongoDB ODM metadata.
31
 *
32
 * @author Kévin Dunglas <dunglas@gmail.com>
33
 * @author Alan Poulain <contact@alanpoulain.eu>
34
 */
35
final class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface
36
{
37
    public function __construct(private readonly ObjectManager $objectManager)
38
    {
UNCOV
39
    }
324✔
40

41
    /**
42
     * {@inheritdoc}
43
     *
44
     * @return string[]|null
45
     */
46
    public function getProperties($class, array $context = []): ?array
47
    {
UNCOV
48
        if (null === $metadata = $this->getMetadata($class)) {
34✔
UNCOV
49
            return null;
34✔
50
        }
51

52
        return $metadata->getFieldNames();
×
53
    }
54

55
    public function getType(string $class, string $property, array $context = []): ?Type
56
    {
UNCOV
57
        if (null === $metadata = $this->getMetadata($class)) {
304✔
UNCOV
58
            return null;
55✔
59
        }
60

UNCOV
61
        if ($metadata->hasAssociation($property)) {
259✔
62
            /** @var class-string|null */
UNCOV
63
            $class = $metadata->getAssociationTargetClass($property);
147✔
64

UNCOV
65
            if (null === $class) {
147✔
UNCOV
66
                return null;
4✔
67
            }
68

UNCOV
69
            if ($metadata->isSingleValuedAssociation($property)) {
146✔
UNCOV
70
                $nullable = $metadata instanceof MongoDbClassMetadata && $metadata->isNullable($property);
133✔
71

UNCOV
72
                return $nullable ? Type::nullable(Type::object($class)) : Type::object($class);
133✔
73
            }
74

UNCOV
75
            return Type::collection(Type::object(Collection::class), Type::object($class), Type::int());
102✔
76
        }
77

UNCOV
78
        if (!$metadata->hasField($property)) {
250✔
UNCOV
79
            return null;
44✔
80
        }
81

UNCOV
82
        $typeOfField = $metadata->getTypeOfField($property);
249✔
83

UNCOV
84
        if (!$typeIdentifier = $this->getTypeIdentifier($typeOfField)) {
249✔
85
            return null;
×
86
        }
87

UNCOV
88
        $nullable = $metadata instanceof MongoDbClassMetadata && $metadata->isNullable($property);
249✔
UNCOV
89
        $enumType = null;
249✔
90

UNCOV
91
        if (null !== $enumClass = $metadata instanceof MongoDbClassMetadata ? $metadata->getFieldMapping($property)['enumType'] ?? null : null) {
249✔
UNCOV
92
            $enumType = $nullable ? Type::nullable(Type::enum($enumClass)) : Type::enum($enumClass);
7✔
93
        }
94

UNCOV
95
        $builtinType = $nullable ? Type::nullable(Type::builtin($typeIdentifier)) : Type::builtin($typeIdentifier);
249✔
96

UNCOV
97
        $type = match ($typeOfField) {
249✔
UNCOV
98
            MongoDbType::DATE => Type::object(\DateTime::class),
249✔
UNCOV
99
            MongoDbType::DATE_IMMUTABLE => Type::object(\DateTimeImmutable::class),
247✔
UNCOV
100
            MongoDbType::HASH => Type::array(),
247✔
UNCOV
101
            MongoDbType::COLLECTION => Type::list(),
247✔
UNCOV
102
            MongoDbType::INT, MongoDbType::INTEGER, MongoDbType::STRING => $enumType ? $enumType : $builtinType,
247✔
UNCOV
103
            default => $builtinType,
71✔
UNCOV
104
        };
249✔
105

UNCOV
106
        return $nullable ? Type::nullable($type) : $type;
249✔
107
    }
108

109
    /**
110
     * {@inheritdoc}
111
     *
112
     * // deprecated since 4.2 use "getType" instead
113
     *
114
     * @return LegacyType[]|null
115
     */
116
    public function getTypes($class, $property, array $context = []): ?array
117
    {
118
        trigger_deprecation('api-platform/core', '4.2', 'The "%s()" method is deprecated, use "%s::getType()" instead.', __METHOD__, self::class);
×
119

120
        if (null === $metadata = $this->getMetadata($class)) {
×
121
            return null;
×
122
        }
123

124
        if ($metadata->hasAssociation($property)) {
×
125
            /** @var class-string|null */
126
            $class = $metadata->getAssociationTargetClass($property);
×
127

128
            if (null === $class) {
×
129
                return null;
×
130
            }
131

132
            if ($metadata->isSingleValuedAssociation($property)) {
×
133
                $nullable = $metadata instanceof MongoDbClassMetadata && $metadata->isNullable($property);
×
134

135
                return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, $class)];
×
136
            }
137

138
            $collectionKeyType = LegacyType::BUILTIN_TYPE_INT;
×
139

140
            return [
×
141
                new LegacyType(
×
142
                    LegacyType::BUILTIN_TYPE_OBJECT,
×
143
                    false,
×
144
                    Collection::class,
×
145
                    true,
×
146
                    new LegacyType($collectionKeyType),
×
147
                    new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, $class)
×
148
                ),
×
149
            ];
×
150
        }
151

152
        if ($metadata->hasField($property)) {
×
153
            $typeOfField = $metadata->getTypeOfField($property);
×
154
            $nullable = $metadata instanceof MongoDbClassMetadata && $metadata->isNullable($property);
×
155
            $enumType = null;
×
156
            if (null !== $enumClass = $metadata instanceof MongoDbClassMetadata ? $metadata->getFieldMapping($property)['enumType'] ?? null : null) {
×
157
                $enumType = new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, $enumClass);
×
158
            }
159

160
            switch ($typeOfField) {
161
                case MongoDbType::DATE:
×
162
                    return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, \DateTime::class)];
×
163
                case MongoDbType::DATE_IMMUTABLE:
×
164
                    return [new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, $nullable, \DateTimeImmutable::class)];
×
165
                case MongoDbType::HASH:
×
166
                    return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
×
167
                case MongoDbType::COLLECTION:
×
168
                    return [new LegacyType(LegacyType::BUILTIN_TYPE_ARRAY, $nullable, null, true, new LegacyType(LegacyType::BUILTIN_TYPE_INT))];
×
169
                case MongoDbType::INT:
×
170
                case MongoDbType::STRING:
×
171
                    if ($enumType) {
×
172
                        return [$enumType];
×
173
                    }
174
            }
175

176
            $builtinType = $this->getNativeTypeLegacy($typeOfField);
×
177

178
            return $builtinType ? [new LegacyType($builtinType, $nullable)] : null;
×
179
        }
180

181
        return null;
×
182
    }
183

184
    /**
185
     * {@inheritdoc}
186
     */
187
    public function isReadable($class, $property, array $context = []): ?bool
188
    {
UNCOV
189
        return null;
166✔
190
    }
191

192
    /**
193
     * {@inheritdoc}
194
     */
195
    public function isWritable($class, $property, array $context = []): ?bool
196
    {
197
        if (
UNCOV
198
            null === ($metadata = $this->getMetadata($class))
323✔
UNCOV
199
            || ($metadata instanceof MongoDbClassMetadata && MongoDbClassMetadata::GENERATOR_TYPE_NONE === $metadata->generatorType)
323✔
UNCOV
200
            || !\in_array($property, $metadata->getIdentifierFieldNames(), true)
323✔
201
        ) {
UNCOV
202
            return null;
321✔
203
        }
204

UNCOV
205
        return false;
252✔
206
    }
207

208
    private function getMetadata(string $class): ?ClassMetadata
209
    {
210
        try {
UNCOV
211
            return $this->objectManager->getClassMetadata($class);
324✔
UNCOV
212
        } catch (MappingException) {
93✔
UNCOV
213
            return null;
93✔
214
        }
215
    }
216

217
    /**
218
     * Gets the corresponding built-in PHP type identifier.
219
     */
220
    private function getTypeIdentifier(string $doctrineType): ?TypeIdentifier
221
    {
UNCOV
222
        return match ($doctrineType) {
UNCOV
223
            MongoDbType::INTEGER, MongoDbType::INT, MongoDbType::INTID, MongoDbType::KEY => TypeIdentifier::INT,
249✔
UNCOV
224
            MongoDbType::FLOAT => TypeIdentifier::FLOAT,
229✔
UNCOV
225
            MongoDbType::STRING, MongoDbType::ID, MongoDbType::OBJECTID, MongoDbType::TIMESTAMP, MongoDbType::BINDATA, MongoDbType::BINDATABYTEARRAY, MongoDbType::BINDATACUSTOM, MongoDbType::BINDATAFUNC, MongoDbType::BINDATAMD5, MongoDbType::BINDATAUUID, MongoDbType::BINDATAUUIDRFC4122 => TypeIdentifier::STRING,
225✔
UNCOV
226
            MongoDbType::BOOLEAN, MongoDbType::BOOL => TypeIdentifier::BOOL,
76✔
UNCOV
227
            MongoDbType::DATE, MongoDbType::DATE_IMMUTABLE => TypeIdentifier::OBJECT,
61✔
UNCOV
228
            MongoDbType::HASH, MongoDbType::COLLECTION => TypeIdentifier::ARRAY,
30✔
UNCOV
229
            default => null,
249✔
UNCOV
230
        };
231
    }
232

233
    private function getNativeTypeLegacy(string $doctrineType): ?string
234
    {
UNCOV
235
        return match ($doctrineType) {
236
            MongoDbType::INTEGER, MongoDbType::INT, MongoDbType::INTID, MongoDbType::KEY => LegacyType::BUILTIN_TYPE_INT,
×
237
            MongoDbType::FLOAT => LegacyType::BUILTIN_TYPE_FLOAT,
×
238
            MongoDbType::STRING, MongoDbType::ID, MongoDbType::OBJECTID, MongoDbType::TIMESTAMP, MongoDbType::BINDATA, MongoDbType::BINDATABYTEARRAY, MongoDbType::BINDATACUSTOM, MongoDbType::BINDATAFUNC, MongoDbType::BINDATAMD5, MongoDbType::BINDATAUUID, MongoDbType::BINDATAUUIDRFC4122 => LegacyType::BUILTIN_TYPE_STRING,
×
239
            MongoDbType::BOOLEAN, MongoDbType::BOOL => LegacyType::BUILTIN_TYPE_BOOL,
×
240
            default => null,
×
UNCOV
241
        };
242
    }
243
}
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