These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Doctrine\ODM\MongoDB\Mapping; |
||
6 | |||
7 | use Doctrine\Common\EventManager; |
||
8 | use Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory; |
||
9 | use Doctrine\Common\Persistence\Mapping\ClassMetadata as ClassMetadataInterface; |
||
10 | use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver; |
||
11 | use Doctrine\Common\Persistence\Mapping\ReflectionService; |
||
12 | use Doctrine\ODM\MongoDB\Configuration; |
||
13 | use Doctrine\ODM\MongoDB\DocumentManager; |
||
14 | use Doctrine\ODM\MongoDB\Event\LoadClassMetadataEventArgs; |
||
15 | use Doctrine\ODM\MongoDB\Events; |
||
16 | use Doctrine\ODM\MongoDB\Id\AbstractIdGenerator; |
||
17 | use Doctrine\ODM\MongoDB\Id\AlnumGenerator; |
||
18 | use Doctrine\ODM\MongoDB\Id\AutoGenerator; |
||
19 | use Doctrine\ODM\MongoDB\Id\IncrementGenerator; |
||
20 | use Doctrine\ODM\MongoDB\Id\UuidGenerator; |
||
21 | use function get_class; |
||
22 | use function get_class_methods; |
||
23 | use function in_array; |
||
24 | use function ucfirst; |
||
25 | |||
26 | /** |
||
27 | * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the |
||
28 | * metadata mapping informations of a class which describes how a class should be mapped |
||
29 | * to a document database. |
||
30 | * |
||
31 | */ |
||
32 | class ClassMetadataFactory extends AbstractClassMetadataFactory |
||
33 | { |
||
34 | /** @var string */ |
||
35 | protected $cacheSalt = '$MONGODBODMCLASSMETADATA'; |
||
36 | |||
37 | /** @var DocumentManager The DocumentManager instance */ |
||
38 | private $dm; |
||
39 | |||
40 | /** @var Configuration The Configuration instance */ |
||
41 | private $config; |
||
42 | |||
43 | /** @var MappingDriver The used metadata driver. */ |
||
44 | private $driver; |
||
45 | |||
46 | /** @var EventManager The event manager instance */ |
||
47 | private $evm; |
||
48 | |||
49 | 1668 | public function setDocumentManager(DocumentManager $dm): void |
|
50 | { |
||
51 | 1668 | $this->dm = $dm; |
|
52 | 1668 | } |
|
53 | |||
54 | 1668 | public function setConfiguration(Configuration $config): void |
|
55 | { |
||
56 | 1668 | $this->config = $config; |
|
57 | 1668 | } |
|
58 | |||
59 | /** |
||
60 | * Lazy initialization of this stuff, especially the metadata driver, |
||
61 | * since these are not needed at all when a metadata cache is active. |
||
62 | */ |
||
63 | 1406 | protected function initialize(): void |
|
64 | { |
||
65 | 1406 | $this->driver = $this->config->getMetadataDriverImpl(); |
|
66 | 1406 | $this->evm = $this->dm->getEventManager(); |
|
67 | 1406 | $this->initialized = true; |
|
68 | 1406 | } |
|
69 | |||
70 | /** |
||
71 | * {@inheritDoc} |
||
72 | */ |
||
73 | protected function getFqcnFromAlias($namespaceAlias, $simpleClassName): string |
||
74 | { |
||
75 | return $this->config->getDocumentNamespace($namespaceAlias) . '\\' . $simpleClassName; |
||
76 | } |
||
77 | |||
78 | /** |
||
79 | * {@inheritDoc} |
||
80 | */ |
||
81 | 913 | protected function getDriver() |
|
82 | { |
||
83 | 913 | return $this->driver; |
|
84 | } |
||
85 | |||
86 | /** |
||
87 | * {@inheritDoc} |
||
88 | */ |
||
89 | 1402 | protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService): void |
|
90 | { |
||
91 | 1402 | } |
|
92 | |||
93 | /** |
||
94 | * {@inheritDoc} |
||
95 | */ |
||
96 | 1406 | protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService): void |
|
97 | { |
||
98 | 1406 | } |
|
99 | |||
100 | /** |
||
101 | * {@inheritDoc} |
||
102 | */ |
||
103 | 1402 | protected function isEntity(ClassMetadataInterface $class): bool |
|
104 | { |
||
105 | 1402 | return ! $class->isMappedSuperclass && ! $class->isEmbeddedDocument && ! $class->isQueryResultDocument; |
|
0 ignored issues
–
show
Accessing
isEmbeddedDocument on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
Loading history...
Accessing
isQueryResultDocument on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
Loading history...
|
|||
106 | } |
||
107 | |||
108 | /** |
||
109 | * {@inheritDoc} |
||
110 | */ |
||
111 | 1406 | protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents = []): void |
|
112 | { |
||
113 | /** @var $class ClassMetadata */ |
||
114 | /** @var $parent ClassMetadata */ |
||
115 | 1406 | if ($parent) { |
|
116 | 911 | $class->setInheritanceType($parent->inheritanceType); |
|
117 | 911 | $class->setDiscriminatorField($parent->discriminatorField); |
|
118 | 911 | $class->setDiscriminatorMap($parent->discriminatorMap); |
|
119 | 911 | $class->setDefaultDiscriminatorValue($parent->defaultDiscriminatorValue); |
|
120 | 911 | $class->setIdGeneratorType($parent->generatorType); |
|
121 | 911 | $this->addInheritedFields($class, $parent); |
|
0 ignored issues
–
show
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata> . It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.
Loading history...
|
|||
122 | 911 | $this->addInheritedRelations($class, $parent); |
|
0 ignored issues
–
show
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata> . It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.
Loading history...
|
|||
123 | 911 | $this->addInheritedIndexes($class, $parent); |
|
0 ignored issues
–
show
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata> . It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.
Loading history...
|
|||
124 | 911 | $this->setInheritedShardKey($class, $parent); |
|
0 ignored issues
–
show
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata> . It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.
Loading history...
|
|||
125 | 911 | $class->setIdentifier($parent->identifier); |
|
126 | 911 | $class->setVersioned($parent->isVersioned); |
|
127 | 911 | $class->setVersionField($parent->versionField); |
|
128 | 911 | $class->setLifecycleCallbacks($parent->lifecycleCallbacks); |
|
129 | 911 | $class->setAlsoLoadMethods($parent->alsoLoadMethods); |
|
130 | 911 | $class->setChangeTrackingPolicy($parent->changeTrackingPolicy); |
|
131 | 911 | $class->setReadPreference($parent->readPreference, $parent->readPreferenceTags); |
|
132 | 911 | $class->setWriteConcern($parent->writeConcern); |
|
133 | 911 | if ($parent->isMappedSuperclass) { |
|
134 | 848 | $class->setCustomRepositoryClass($parent->customRepositoryClassName); |
|
135 | } |
||
136 | } |
||
137 | |||
138 | // Invoke driver |
||
139 | try { |
||
140 | 1406 | $this->driver->loadMetadataForClass($class->getName(), $class); |
|
141 | 6 | } catch (\ReflectionException $e) { |
|
142 | throw MappingException::reflectionFailure($class->getName(), $e); |
||
143 | } |
||
144 | |||
145 | 1402 | $this->validateIdentifier($class); |
|
0 ignored issues
–
show
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata> . It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.
Loading history...
|
|||
146 | |||
147 | 1402 | if ($parent && $rootEntityFound && $parent->generatorType === $class->generatorType) { |
|
0 ignored issues
–
show
Accessing
generatorType on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
Loading history...
|
|||
148 | 118 | if ($parent->generatorType) { |
|
149 | 118 | $class->setIdGeneratorType($parent->generatorType); |
|
150 | } |
||
151 | 118 | if ($parent->generatorOptions) { |
|
152 | $class->setIdGeneratorOptions($parent->generatorOptions); |
||
153 | } |
||
154 | 118 | if ($parent->idGenerator) { |
|
155 | 118 | $class->setIdGenerator($parent->idGenerator); |
|
156 | } |
||
157 | } else { |
||
158 | 1402 | $this->completeIdGeneratorMapping($class); |
|
0 ignored issues
–
show
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata> . It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.
Loading history...
|
|||
159 | } |
||
160 | |||
161 | 1402 | if ($parent && $parent->isInheritanceTypeSingleCollection()) { |
|
162 | 107 | $class->setDatabase($parent->getDatabase()); |
|
163 | 107 | $class->setCollection($parent->getCollection()); |
|
164 | } |
||
165 | |||
166 | 1402 | $class->setParentClasses($nonSuperclassParents); |
|
167 | |||
168 | 1402 | if (! $this->evm->hasListeners(Events::loadClassMetadata)) { |
|
169 | 1400 | return; |
|
170 | } |
||
171 | |||
172 | 2 | $eventArgs = new LoadClassMetadataEventArgs($class, $this->dm); |
|
173 | 2 | $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs); |
|
174 | 2 | } |
|
175 | |||
176 | /** |
||
177 | * Validates the identifier mapping. |
||
178 | * |
||
179 | * @throws MappingException |
||
180 | */ |
||
181 | 1402 | protected function validateIdentifier(ClassMetadata $class): void |
|
182 | { |
||
183 | 1402 | if (! $class->identifier && ! $class->isMappedSuperclass && ! $class->isEmbeddedDocument && ! $class->isQueryResultDocument) { |
|
184 | throw MappingException::identifierRequired($class->name); |
||
185 | } |
||
186 | 1402 | } |
|
187 | |||
188 | /** |
||
189 | * {@inheritdoc} |
||
190 | */ |
||
191 | 1406 | protected function newClassMetadataInstance($className): ClassMetadata |
|
192 | { |
||
193 | 1406 | return new ClassMetadata($className); |
|
194 | } |
||
195 | |||
196 | 1402 | private function completeIdGeneratorMapping(ClassMetadata $class): void |
|
197 | { |
||
198 | 1402 | $idGenOptions = $class->generatorOptions; |
|
199 | 1402 | switch ($class->generatorType) { |
|
200 | case ClassMetadata::GENERATOR_TYPE_AUTO: |
||
201 | 1334 | $class->setIdGenerator(new AutoGenerator()); |
|
202 | 1334 | break; |
|
203 | View Code Duplication | case ClassMetadata::GENERATOR_TYPE_INCREMENT: |
|
204 | 9 | $incrementGenerator = new IncrementGenerator(); |
|
205 | 9 | if (isset($idGenOptions['key'])) { |
|
206 | $incrementGenerator->setKey((string) $idGenOptions['key']); |
||
207 | } |
||
208 | 9 | if (isset($idGenOptions['collection'])) { |
|
209 | $incrementGenerator->setCollection((string) $idGenOptions['collection']); |
||
210 | } |
||
211 | 9 | if (isset($idGenOptions['startingId'])) { |
|
212 | 1 | $incrementGenerator->setStartingId((int) $idGenOptions['startingId']); |
|
213 | } |
||
214 | 9 | $class->setIdGenerator($incrementGenerator); |
|
215 | 9 | break; |
|
216 | case ClassMetadata::GENERATOR_TYPE_UUID: |
||
217 | 4 | $uuidGenerator = new UuidGenerator(); |
|
218 | 4 | isset($idGenOptions['salt']) && $uuidGenerator->setSalt((string) $idGenOptions['salt']); |
|
219 | 4 | $class->setIdGenerator($uuidGenerator); |
|
220 | 4 | break; |
|
221 | View Code Duplication | case ClassMetadata::GENERATOR_TYPE_ALNUM: |
|
222 | 1 | $alnumGenerator = new AlnumGenerator(); |
|
223 | 1 | if (isset($idGenOptions['pad'])) { |
|
224 | $alnumGenerator->setPad((int) $idGenOptions['pad']); |
||
225 | } |
||
226 | 1 | if (isset($idGenOptions['chars'])) { |
|
227 | 1 | $alnumGenerator->setChars((string) $idGenOptions['chars']); |
|
228 | } elseif (isset($idGenOptions['awkwardSafe'])) { |
||
229 | $alnumGenerator->setAwkwardSafeMode((bool) $idGenOptions['awkwardSafe']); |
||
230 | } |
||
231 | |||
232 | 1 | $class->setIdGenerator($alnumGenerator); |
|
233 | 1 | break; |
|
234 | case ClassMetadata::GENERATOR_TYPE_CUSTOM: |
||
235 | if (empty($idGenOptions['class'])) { |
||
236 | throw MappingException::missingIdGeneratorClass($class->name); |
||
237 | } |
||
238 | |||
239 | $customGenerator = new $idGenOptions['class'](); |
||
240 | unset($idGenOptions['class']); |
||
241 | if (! $customGenerator instanceof AbstractIdGenerator) { |
||
242 | throw MappingException::classIsNotAValidGenerator(get_class($customGenerator)); |
||
243 | } |
||
244 | |||
245 | $methods = get_class_methods($customGenerator); |
||
246 | foreach ($idGenOptions as $name => $value) { |
||
247 | $method = 'set' . ucfirst($name); |
||
248 | if (! in_array($method, $methods)) { |
||
249 | throw MappingException::missingGeneratorSetter(get_class($customGenerator), $name); |
||
250 | } |
||
251 | |||
252 | $customGenerator->$method($value); |
||
253 | } |
||
254 | $class->setIdGenerator($customGenerator); |
||
255 | break; |
||
256 | case ClassMetadata::GENERATOR_TYPE_NONE: |
||
257 | 150 | break; |
|
258 | default: |
||
259 | throw new MappingException('Unknown generator type: ' . $class->generatorType); |
||
260 | } |
||
261 | 1402 | } |
|
262 | |||
263 | /** |
||
264 | * Adds inherited fields to the subclass mapping. |
||
265 | */ |
||
266 | 911 | private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass): void |
|
267 | { |
||
268 | 911 | foreach ($parentClass->fieldMappings as $fieldName => $mapping) { |
|
269 | 136 | View Code Duplication | if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) { |
270 | 130 | $mapping['inherited'] = $parentClass->name; |
|
271 | } |
||
272 | 136 | if (! isset($mapping['declared'])) { |
|
273 | 136 | $mapping['declared'] = $parentClass->name; |
|
274 | } |
||
275 | 136 | $subClass->addInheritedFieldMapping($mapping); |
|
276 | } |
||
277 | 911 | foreach ($parentClass->reflFields as $name => $field) { |
|
278 | 136 | $subClass->reflFields[$name] = $field; |
|
279 | } |
||
280 | 911 | } |
|
281 | |||
282 | |||
283 | /** |
||
284 | * Adds inherited association mappings to the subclass mapping. |
||
285 | * |
||
286 | * @throws MappingException |
||
287 | */ |
||
288 | 911 | private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass): void |
|
289 | { |
||
290 | 911 | foreach ($parentClass->associationMappings as $field => $mapping) { |
|
291 | 87 | if ($parentClass->isMappedSuperclass) { |
|
292 | 4 | $mapping['sourceDocument'] = $subClass->name; |
|
293 | } |
||
294 | |||
295 | 87 | View Code Duplication | if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) { |
296 | 83 | $mapping['inherited'] = $parentClass->name; |
|
297 | } |
||
298 | 87 | if (! isset($mapping['declared'])) { |
|
299 | 87 | $mapping['declared'] = $parentClass->name; |
|
300 | } |
||
301 | 87 | $subClass->addInheritedAssociationMapping($mapping); |
|
302 | } |
||
303 | 911 | } |
|
304 | |||
305 | /** |
||
306 | * Adds inherited indexes to the subclass mapping. |
||
307 | */ |
||
308 | 911 | private function addInheritedIndexes(ClassMetadata $subClass, ClassMetadata $parentClass): void |
|
309 | { |
||
310 | 911 | foreach ($parentClass->indexes as $index) { |
|
311 | 65 | $subClass->addIndex($index['keys'], $index['options']); |
|
312 | } |
||
313 | 911 | } |
|
314 | |||
315 | /** |
||
316 | * Adds inherited shard key to the subclass mapping. |
||
317 | */ |
||
318 | 911 | private function setInheritedShardKey(ClassMetadata $subClass, ClassMetadata $parentClass): void |
|
319 | { |
||
320 | 911 | if (! $parentClass->isSharded()) { |
|
321 | 906 | return; |
|
322 | } |
||
323 | |||
324 | 5 | $subClass->setShardKey( |
|
325 | 5 | $parentClass->shardKey['keys'], |
|
326 | 5 | $parentClass->shardKey['options'] |
|
0 ignored issues
–
show
$parentClass->shardKey['options'] is of type string , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
327 | ); |
||
328 | 5 | } |
|
329 | } |
||
330 |
If you access a property on an interface, you most likely code against a concrete implementation of the interface.
Available Fixes
Adding an additional type check:
Changing the type hint: