Completed
Push — master ( 7b9f4b...1cd743 )
by Andreas
13s queued 10s
created

ODM/MongoDB/Mapping/ClassMetadataFactory.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

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\ConfigurationException;
14
use Doctrine\ODM\MongoDB\DocumentManager;
15
use Doctrine\ODM\MongoDB\Event\LoadClassMetadataEventArgs;
16
use Doctrine\ODM\MongoDB\Events;
17
use Doctrine\ODM\MongoDB\Id\AbstractIdGenerator;
18
use Doctrine\ODM\MongoDB\Id\AlnumGenerator;
19
use Doctrine\ODM\MongoDB\Id\AutoGenerator;
20
use Doctrine\ODM\MongoDB\Id\IncrementGenerator;
21
use Doctrine\ODM\MongoDB\Id\UuidGenerator;
22
use ReflectionException;
23
use function assert;
24
use function get_class;
25
use function get_class_methods;
26
use function in_array;
27
use function ucfirst;
28
29
/**
30
 * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
31
 * metadata mapping informations of a class which describes how a class should be mapped
32
 * to a document database.
33
 */
34
class ClassMetadataFactory extends AbstractClassMetadataFactory
35
{
36
    /** @var string */
37
    protected $cacheSalt = '$MONGODBODMCLASSMETADATA';
38
39
    /** @var DocumentManager The DocumentManager instance */
40
    private $dm;
41
42
    /** @var Configuration The Configuration instance */
43
    private $config;
44
45
    /** @var MappingDriver The used metadata driver. */
46
    private $driver;
47
48
    /** @var EventManager The event manager instance */
49
    private $evm;
50
51 1757
    public function setDocumentManager(DocumentManager $dm) : void
52
    {
53 1757
        $this->dm = $dm;
54 1757
    }
55
56 1757
    public function setConfiguration(Configuration $config) : void
57
    {
58 1757
        $this->config = $config;
59 1757
    }
60
61 1485
    public function getMetadataFor($className)
62
    {
63 1485
        return parent::getMetadataFor($this->dm->getClassNameResolver()->getRealClass($className));
64
    }
65
66
    /**
67
     * Lazy initialization of this stuff, especially the metadata driver,
68
     * since these are not needed at all when a metadata cache is active.
69
     */
70 1484
    protected function initialize() : void
71
    {
72 1484
        $driver = $this->config->getMetadataDriverImpl();
73 1484
        if ($driver === null) {
74
            throw ConfigurationException::noMetadataDriverConfigured();
75
        }
76
77 1484
        $this->driver      = $driver;
78 1484
        $this->evm         = $this->dm->getEventManager();
79 1484
        $this->initialized = true;
80 1484
    }
81
82
    /**
83
     * {@inheritDoc}
84
     */
85
    protected function getFqcnFromAlias($namespaceAlias, $simpleClassName) : string
86
    {
87
        return $this->config->getDocumentNamespace($namespaceAlias) . '\\' . $simpleClassName;
88
    }
89
90
    /**
91
     * {@inheritDoc}
92
     */
93 960
    protected function getDriver()
94
    {
95 960
        return $this->driver;
96
    }
97
98
    /**
99
     * {@inheritDoc}
100
     */
101 1480
    protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService) : void
102
    {
103 1480
    }
104
105
    /**
106
     * {@inheritDoc}
107
     */
108 1484
    protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService) : void
109
    {
110 1484
    }
111
112
    /**
113
     * {@inheritDoc}
114
     */
115 1480
    protected function isEntity(ClassMetadataInterface $class) : bool
116
    {
117 1480
        assert($class instanceof ClassMetadata);
118 1480
        return ! $class->isMappedSuperclass && ! $class->isEmbeddedDocument && ! $class->isQueryResultDocument;
119
    }
120
121
    /**
122
     * {@inheritDoc}
123
     */
124 1484
    protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents = []) : void
125
    {
126 1484
        assert($class instanceof ClassMetadata);
127 1484
        if ($parent instanceof ClassMetadata) {
128 958
            $class->setInheritanceType($parent->inheritanceType);
129 958
            $class->setDiscriminatorField($parent->discriminatorField);
130 958
            $class->setDiscriminatorMap($parent->discriminatorMap);
131 958
            $class->setDefaultDiscriminatorValue($parent->defaultDiscriminatorValue);
132 958
            $class->setIdGeneratorType($parent->generatorType);
133 958
            $this->addInheritedFields($class, $parent);
134 958
            $this->addInheritedRelations($class, $parent);
135 958
            $this->addInheritedIndexes($class, $parent);
136 958
            $this->setInheritedShardKey($class, $parent);
137 958
            $class->setIdentifier($parent->identifier);
138 958
            $class->setVersioned($parent->isVersioned);
139 958
            $class->setVersionField($parent->versionField);
140 958
            $class->setLifecycleCallbacks($parent->lifecycleCallbacks);
141 958
            $class->setAlsoLoadMethods($parent->alsoLoadMethods);
142 958
            $class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
143 958
            $class->setReadPreference($parent->readPreference, $parent->readPreferenceTags);
144 958
            $class->setWriteConcern($parent->writeConcern);
145
146 958
            if ($parent->isMappedSuperclass) {
147 894
                $class->setCustomRepositoryClass($parent->customRepositoryClassName);
148
            }
149
150 958
            if ($parent->isFile) {
151 1
                $class->isFile = true;
152 1
                $class->setBucketName($parent->bucketName);
153
154 1
                if ($parent->chunkSizeBytes !== null) {
155 1
                    $class->setChunkSizeBytes($parent->chunkSizeBytes);
156
                }
157
            }
158
        }
159
160
        // Invoke driver
161
        try {
162 1484
            $this->driver->loadMetadataForClass($class->getName(), $class);
0 ignored issues
show
Consider using $class->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
163 6
        } catch (ReflectionException $e) {
164
            throw MappingException::reflectionFailure($class->getName(), $e);
0 ignored issues
show
Consider using $class->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
165
        }
166
167 1480
        $this->validateIdentifier($class);
168
169 1480
        if ($parent instanceof ClassMetadata && $rootEntityFound && $parent->generatorType === $class->generatorType) {
170 164
            if ($parent->generatorType) {
171 164
                $class->setIdGeneratorType($parent->generatorType);
172
            }
173 164
            if ($parent->generatorOptions) {
174
                $class->setIdGeneratorOptions($parent->generatorOptions);
175
            }
176 164
            if ($parent->idGenerator) {
177 164
                $class->setIdGenerator($parent->idGenerator);
178
            }
179
        } else {
180 1480
            $this->completeIdGeneratorMapping($class);
181
        }
182
183 1480
        if ($parent instanceof ClassMetadata && $parent->isInheritanceTypeSingleCollection()) {
184 150
            $class->setDatabase($parent->getDatabase());
185 150
            $class->setCollection($parent->getCollection());
186
        }
187
188 1480
        $class->setParentClasses($nonSuperclassParents);
189
190 1480
        if (! $this->evm->hasListeners(Events::loadClassMetadata)) {
191 1478
            return;
192
        }
193
194 2
        $eventArgs = new LoadClassMetadataEventArgs($class, $this->dm);
195 2
        $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
196 2
    }
197
198
    /**
199
     * Validates the identifier mapping.
200
     *
201
     * @throws MappingException
202
     */
203 1480
    protected function validateIdentifier(ClassMetadata $class) : void
204
    {
205 1480
        if (! $class->identifier && ! $class->isMappedSuperclass && ! $class->isEmbeddedDocument && ! $class->isQueryResultDocument) {
206
            throw MappingException::identifierRequired($class->name);
207
        }
208 1480
    }
209
210
    /**
211
     * {@inheritdoc}
212
     */
213 1484
    protected function newClassMetadataInstance($className) : ClassMetadata
214
    {
215 1484
        return new ClassMetadata($className);
216
    }
217
218 1480
    private function completeIdGeneratorMapping(ClassMetadata $class) : void
219
    {
220 1480
        $idGenOptions = $class->generatorOptions;
221 1480
        switch ($class->generatorType) {
222
            case ClassMetadata::GENERATOR_TYPE_AUTO:
223 1412
                $class->setIdGenerator(new AutoGenerator());
224 1412
                break;
225 View Code Duplication
            case ClassMetadata::GENERATOR_TYPE_INCREMENT:
226 9
                $incrementGenerator = new IncrementGenerator();
227 9
                if (isset($idGenOptions['key'])) {
228
                    $incrementGenerator->setKey((string) $idGenOptions['key']);
229
                }
230 9
                if (isset($idGenOptions['collection'])) {
231
                    $incrementGenerator->setCollection((string) $idGenOptions['collection']);
232
                }
233 9
                if (isset($idGenOptions['startingId'])) {
234 1
                    $incrementGenerator->setStartingId((int) $idGenOptions['startingId']);
235
                }
236 9
                $class->setIdGenerator($incrementGenerator);
237 9
                break;
238
            case ClassMetadata::GENERATOR_TYPE_UUID:
239 4
                $uuidGenerator = new UuidGenerator();
240 4
                if (isset($idGenOptions['salt'])) {
241 2
                    $uuidGenerator->setSalt((string) $idGenOptions['salt']);
242
                }
243 4
                $class->setIdGenerator($uuidGenerator);
244 4
                break;
245 View Code Duplication
            case ClassMetadata::GENERATOR_TYPE_ALNUM:
246 1
                $alnumGenerator = new AlnumGenerator();
247 1
                if (isset($idGenOptions['pad'])) {
248
                    $alnumGenerator->setPad((int) $idGenOptions['pad']);
249
                }
250 1
                if (isset($idGenOptions['chars'])) {
251 1
                    $alnumGenerator->setChars((string) $idGenOptions['chars']);
252
                } elseif (isset($idGenOptions['awkwardSafe'])) {
253
                    $alnumGenerator->setAwkwardSafeMode((bool) $idGenOptions['awkwardSafe']);
254
                }
255
256 1
                $class->setIdGenerator($alnumGenerator);
257 1
                break;
258
            case ClassMetadata::GENERATOR_TYPE_CUSTOM:
259
                if (empty($idGenOptions['class'])) {
260
                    throw MappingException::missingIdGeneratorClass($class->name);
261
                }
262
263
                $customGenerator = new $idGenOptions['class']();
264
                unset($idGenOptions['class']);
265
                if (! $customGenerator instanceof AbstractIdGenerator) {
266
                    throw MappingException::classIsNotAValidGenerator(get_class($customGenerator));
267
                }
268
269
                $methods = get_class_methods($customGenerator);
270
                foreach ($idGenOptions as $name => $value) {
271
                    $method = 'set' . ucfirst($name);
272
                    if (! in_array($method, $methods)) {
273
                        throw MappingException::missingGeneratorSetter(get_class($customGenerator), $name);
274
                    }
275
276
                    $customGenerator->$method($value);
277
                }
278
                $class->setIdGenerator($customGenerator);
279
                break;
280
            case ClassMetadata::GENERATOR_TYPE_NONE:
281 193
                break;
282
            default:
283
                throw new MappingException('Unknown generator type: ' . $class->generatorType);
284
        }
285 1480
    }
286
287
    /**
288
     * Adds inherited fields to the subclass mapping.
289
     */
290 958
    private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass) : void
291
    {
292 958
        foreach ($parentClass->fieldMappings as $fieldName => $mapping) {
293 182 View Code Duplication
            if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
294 176
                $mapping['inherited'] = $parentClass->name;
295
            }
296 182
            if (! isset($mapping['declared'])) {
297 182
                $mapping['declared'] = $parentClass->name;
298
            }
299 182
            $subClass->addInheritedFieldMapping($mapping);
300
        }
301 958
        foreach ($parentClass->reflFields as $name => $field) {
302 182
            $subClass->reflFields[$name] = $field;
303
        }
304 958
    }
305
306
307
    /**
308
     * Adds inherited association mappings to the subclass mapping.
309
     *
310
     * @throws MappingException
311
     */
312 958
    private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass) : void
313
    {
314 958
        foreach ($parentClass->associationMappings as $field => $mapping) {
315 132
            if ($parentClass->isMappedSuperclass) {
316 4
                $mapping['sourceDocument'] = $subClass->name;
317
            }
318
319 132 View Code Duplication
            if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
320 128
                $mapping['inherited'] = $parentClass->name;
321
            }
322 132
            if (! isset($mapping['declared'])) {
323 132
                $mapping['declared'] = $parentClass->name;
324
            }
325 132
            $subClass->addInheritedAssociationMapping($mapping);
326
        }
327 958
    }
328
329
    /**
330
     * Adds inherited indexes to the subclass mapping.
331
     */
332 958
    private function addInheritedIndexes(ClassMetadata $subClass, ClassMetadata $parentClass) : void
333
    {
334 958
        foreach ($parentClass->indexes as $index) {
335 108
            $subClass->addIndex($index['keys'], $index['options']);
336
        }
337 958
    }
338
339
    /**
340
     * Adds inherited shard key to the subclass mapping.
341
     */
342 958
    private function setInheritedShardKey(ClassMetadata $subClass, ClassMetadata $parentClass) : void
343
    {
344 958
        if (! $parentClass->isSharded()) {
345 953
            return;
346
        }
347
348 5
        $subClass->setShardKey(
349 5
            $parentClass->shardKey['keys'],
350 5
            $parentClass->shardKey['options']
351
        );
352 5
    }
353
}
354