Failed Conditions
Push — master ( 6744b4...2b8acb )
by Marco
60:45 queued 60:36
created

Tests/ORM/Mapping/ClassMetadataFactoryTest.php (1 issue)

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
namespace Doctrine\Tests\ORM\Mapping;
4
5
use Doctrine\Common\EventManager;
6
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
7
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
8
use Doctrine\DBAL\Connection;
9
use Doctrine\ORM\Configuration;
10
use Doctrine\ORM\EntityManager;
11
use Doctrine\ORM\EntityManagerInterface;
12
use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs;
13
use Doctrine\ORM\Events;
14
use Doctrine\ORM\Id\AbstractIdGenerator;
15
use Doctrine\ORM\Mapping\ClassMetadata;
16
use Doctrine\ORM\Mapping\ClassMetadataFactory;
17
use Doctrine\ORM\Mapping\MappingException;
18
use Doctrine\ORM\ORMException;
19
use Doctrine\Tests\Mocks\ConnectionMock;
20
use Doctrine\Tests\Mocks\DriverMock;
21
use Doctrine\Tests\Mocks\EntityManagerMock;
22
use Doctrine\Tests\Mocks\MetadataDriverMock;
23
use Doctrine\Tests\Models\CMS\CmsArticle;
24
use Doctrine\Tests\Models\CMS\CmsUser;
25
use Doctrine\Tests\Models\DDC4006\DDC4006User;
26
use Doctrine\Tests\Models\JoinedInheritanceType\AnotherChildClass;
27
use Doctrine\Tests\Models\JoinedInheritanceType\ChildClass;
28
use Doctrine\Tests\Models\JoinedInheritanceType\RootClass;
29
use Doctrine\Tests\Models\Quote;
30
use Doctrine\Tests\OrmTestCase;
31
use DoctrineGlobal_Article;
32
33
class ClassMetadataFactoryTest extends OrmTestCase
34
{
35
    public function testGetMetadataForSingleClass()
36
    {
37
        $mockDriver = new MetadataDriverMock();
38
        $entityManager = $this->_createEntityManager($mockDriver);
39
40
        $conn = $entityManager->getConnection();
41
        $mockPlatform = $conn->getDatabasePlatform();
42
        $mockPlatform->setPrefersSequences(true);
43
        $mockPlatform->setPrefersIdentityColumns(false);
44
45
        $cm1 = $this->_createValidClassMetadata();
46
47
        // SUT
48
        $cmf = new ClassMetadataFactory();
49
        $cmf->setEntityManager($entityManager);
50
        $cmf->setMetadataFor($cm1->name, $cm1);
51
52
        // Prechecks
53
        $this->assertEquals([], $cm1->parentClasses);
54
        $this->assertEquals(ClassMetadata::INHERITANCE_TYPE_NONE, $cm1->inheritanceType);
55
        $this->assertTrue($cm1->hasField('name'));
56
        $this->assertEquals(2, count($cm1->associationMappings));
57
        $this->assertEquals(ClassMetadata::GENERATOR_TYPE_AUTO, $cm1->generatorType);
58
        $this->assertEquals('group', $cm1->table['name']);
59
60
        // Go
61
        $cmMap1 = $cmf->getMetadataFor($cm1->name);
62
63
        $this->assertSame($cm1, $cmMap1);
64
        $this->assertEquals('group', $cmMap1->table['name']);
65
        $this->assertTrue($cmMap1->table['quoted']);
66
        $this->assertEquals([], $cmMap1->parentClasses);
67
        $this->assertTrue($cmMap1->hasField('name'));
68
    }
69
70
    public function testGetMetadataFor_ReturnsLoadedCustomIdGenerator()
71
    {
72
        $cm1 = $this->_createValidClassMetadata();
73
        $cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_CUSTOM);
74
        $cm1->customGeneratorDefinition = ['class' => CustomIdGenerator::class];
75
        $cmf = $this->_createTestFactory();
76
        $cmf->setMetadataForClass($cm1->name, $cm1);
77
78
        $actual = $cmf->getMetadataFor($cm1->name);
79
80
        $this->assertEquals(ClassMetadata::GENERATOR_TYPE_CUSTOM, $actual->generatorType);
81
        $this->assertInstanceOf(CustomIdGenerator::class, $actual->idGenerator);
82
    }
83
84 View Code Duplication
    public function testGetMetadataFor_ThrowsExceptionOnUnknownCustomGeneratorClass()
85
    {
86
        $cm1 = $this->_createValidClassMetadata();
87
        $cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_CUSTOM);
88
        $cm1->customGeneratorDefinition = ["class" => "NotExistingGenerator"];
89
        $cmf = $this->_createTestFactory();
90
        $cmf->setMetadataForClass($cm1->name, $cm1);
91
        $this->expectException(ORMException::class);
92
93
        $actual = $cmf->getMetadataFor($cm1->name);
94
    }
95
96 View Code Duplication
    public function testGetMetadataFor_ThrowsExceptionOnMissingCustomGeneratorDefinition()
97
    {
98
        $cm1 = $this->_createValidClassMetadata();
99
        $cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_CUSTOM);
100
        $cmf = $this->_createTestFactory();
101
        $cmf->setMetadataForClass($cm1->name, $cm1);
102
        $this->expectException(ORMException::class);
103
104
        $actual = $cmf->getMetadataFor($cm1->name);
105
    }
106
107
    public function testHasGetMetadata_NamespaceSeparatorIsNotNormalized()
108
    {
109
        require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php";
110
111
        $metadataDriver = $this->createAnnotationDriver([__DIR__ . '/../../Models/Global/']);
112
113
        $entityManager = $this->_createEntityManager($metadataDriver);
114
115
        $mf = $entityManager->getMetadataFactory();
116
        $m1 = $mf->getMetadataFor(DoctrineGlobal_Article::class);
117
        $h1 = $mf->hasMetadataFor(DoctrineGlobal_Article::class);
118
        $h2 = $mf->hasMetadataFor('\\' . DoctrineGlobal_Article::class);
119
        $m2 = $mf->getMetadataFor('\\' . DoctrineGlobal_Article::class);
120
121
        $this->assertNotSame($m1, $m2);
122
        $this->assertFalse($h2);
123
        $this->assertTrue($h1);
124
    }
125
126
    /**
127
     * @group DDC-1512
128
     */
129
    public function testIsTransient()
130
    {
131
        $cmf = new ClassMetadataFactory();
132
        $driver = $this->createMock(MappingDriver::class);
133
        $driver->expects($this->at(0))
134
               ->method('isTransient')
135
               ->with($this->equalTo(CmsUser::class))
136
               ->will($this->returnValue(true));
137
        $driver->expects($this->at(1))
138
               ->method('isTransient')
139
               ->with($this->equalTo(CmsArticle::class))
140
               ->will($this->returnValue(false));
141
142
        $em = $this->_createEntityManager($driver);
143
144
        $this->assertTrue($em->getMetadataFactory()->isTransient(CmsUser::class));
145
        $this->assertFalse($em->getMetadataFactory()->isTransient(CmsArticle::class));
146
    }
147
148
    /**
149
     * @group DDC-1512
150
     */
151
    public function testIsTransientEntityNamespace()
152
    {
153
        $cmf = new ClassMetadataFactory();
154
        $driver = $this->createMock(MappingDriver::class);
155
        $driver->expects($this->at(0))
156
               ->method('isTransient')
157
               ->with($this->equalTo(CmsUser::class))
158
               ->will($this->returnValue(true));
159
        $driver->expects($this->at(1))
160
               ->method('isTransient')
161
               ->with($this->equalTo(CmsArticle::class))
162
               ->will($this->returnValue(false));
163
164
        $em = $this->_createEntityManager($driver);
165
        $em->getConfiguration()->addEntityNamespace('CMS', 'Doctrine\Tests\Models\CMS');
166
167
        $this->assertTrue($em->getMetadataFactory()->isTransient('CMS:CmsUser'));
168
        $this->assertFalse($em->getMetadataFactory()->isTransient('CMS:CmsArticle'));
169
    }
170
171
    public function testAddDefaultDiscriminatorMap()
172
    {
173
        $cmf = new ClassMetadataFactory();
174
        $driver = $this->createAnnotationDriver([__DIR__ . '/../../Models/JoinedInheritanceType/']);
175
        $em = $this->_createEntityManager($driver);
176
        $cmf->setEntityManager($em);
177
178
        $rootMetadata = $cmf->getMetadataFor(RootClass::class);
179
        $childMetadata = $cmf->getMetadataFor(ChildClass::class);
180
        $anotherChildMetadata = $cmf->getMetadataFor(AnotherChildClass::class);
181
        $rootDiscriminatorMap = $rootMetadata->discriminatorMap;
182
        $childDiscriminatorMap = $childMetadata->discriminatorMap;
183
        $anotherChildDiscriminatorMap = $anotherChildMetadata->discriminatorMap;
184
185
        $rootClass = RootClass::class;
186
        $childClass = ChildClass::class;
187
        $anotherChildClass = AnotherChildClass::class;
188
189
        $rootClassKey = array_search($rootClass, $rootDiscriminatorMap);
190
        $childClassKey = array_search($childClass, $rootDiscriminatorMap);
191
        $anotherChildClassKey = array_search($anotherChildClass, $rootDiscriminatorMap);
192
193
        $this->assertEquals('rootclass', $rootClassKey);
194
        $this->assertEquals('childclass', $childClassKey);
195
        $this->assertEquals('anotherchildclass', $anotherChildClassKey);
196
197
        $this->assertEquals($childDiscriminatorMap, $rootDiscriminatorMap);
198
        $this->assertEquals($anotherChildDiscriminatorMap, $rootDiscriminatorMap);
199
200
        // ClassMetadataFactory::addDefaultDiscriminatorMap shouldn't be called again, because the
201
        // discriminator map is already cached
202
        $cmf = $this->getMockBuilder(ClassMetadataFactory::class)->setMethods(['addDefaultDiscriminatorMap'])->getMock();
203
        $cmf->setEntityManager($em);
204
        $cmf->expects($this->never())
205
            ->method('addDefaultDiscriminatorMap');
206
207
        $rootMetadata = $cmf->getMetadataFor(RootClass::class);
208
    }
209
210
    public function testGetAllMetadataWorksWithBadConnection()
211
    {
212
        // DDC-3551
213
        $conn = $this->createMock(Connection::class);
214
        $mockDriver    = new MetadataDriverMock();
215
        $em = $this->_createEntityManager($mockDriver, $conn);
216
217
        $conn->expects($this->any())
218
            ->method('getDatabasePlatform')
219
            ->will($this->throwException(new \Exception('Exception thrown in test when calling getDatabasePlatform')));
220
221
        $cmf = new ClassMetadataFactory();
222
        $cmf->setEntityManager($em);
223
224
        // getting all the metadata should work, even if get DatabasePlatform blows up
225
        $metadata = $cmf->getAllMetadata();
226
        // this will just be an empty array - there was no error
227
        $this->assertEquals([], $metadata);
228
    }
229
230 View Code Duplication
    protected function _createEntityManager($metadataDriver, $conn = null)
231
    {
232
        $driverMock = new DriverMock();
233
        $config = new Configuration();
234
        $config->setProxyDir(__DIR__ . '/../../Proxies');
235
        $config->setProxyNamespace('Doctrine\Tests\Proxies');
236
        $eventManager = new EventManager();
237
        if (!$conn) {
238
            $conn = new ConnectionMock([], $driverMock, $config, $eventManager);
239
        }
240
        $config->setMetadataDriverImpl($metadataDriver);
241
242
        return EntityManagerMock::create($conn, $config, $eventManager);
243
    }
244
245
    /**
246
     * @return ClassMetadataFactoryTestSubject
247
     */
248
    protected function _createTestFactory()
249
    {
250
        $mockDriver = new MetadataDriverMock();
251
        $entityManager = $this->_createEntityManager($mockDriver);
252
        $cmf = new ClassMetadataFactoryTestSubject();
253
        $cmf->setEntityManager($entityManager);
254
        return $cmf;
255
    }
256
257
    /**
258
     * @param string $class
0 ignored issues
show
There is no parameter named $class. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
259
     * @return ClassMetadata
260
     */
261
    protected function _createValidClassMetadata()
262
    {
263
        // Self-made metadata
264
        $cm1 = new ClassMetadata(TestEntity1::class);
265
        $cm1->initializeReflection(new RuntimeReflectionService());
266
        $cm1->setPrimaryTable(['name' => '`group`']);
267
        // Add a mapped field
268
        $cm1->mapField(['fieldName' => 'name', 'type' => 'string']);
269
        // Add a mapped field
270
        $cm1->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
271
        // and a mapped association
272
        $cm1->mapOneToOne(['fieldName' => 'other', 'targetEntity' => 'TestEntity1', 'mappedBy' => 'this']);
273
        // and an association on the owning side
274
        $joinColumns = [
275
            ['name' => 'other_id', 'referencedColumnName' => 'id']
276
        ];
277
        $cm1->mapOneToOne(
278
            ['fieldName' => 'association', 'targetEntity' => 'TestEntity1', 'joinColumns' => $joinColumns]
279
        );
280
        // and an id generator type
281
        $cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);
282
        return $cm1;
283
    }
284
285
    /**
286
    * @group DDC-1845
287
    */
288
    public function testQuoteMetadata()
289
    {
290
        $cmf    = new ClassMetadataFactory();
291
        $driver = $this->createAnnotationDriver([__DIR__ . '/../../Models/Quote/']);
292
        $em     = $this->_createEntityManager($driver);
293
        $cmf->setEntityManager($em);
294
295
296
        $userMetadata       = $cmf->getMetadataFor(Quote\User::class);
297
        $phoneMetadata      = $cmf->getMetadataFor(Quote\Phone::class);
298
        $groupMetadata      = $cmf->getMetadataFor(Quote\Group::class);
299
        $addressMetadata    = $cmf->getMetadataFor(Quote\Address::class);
300
301
302
        // Phone Class Metadata
303
        $this->assertTrue($phoneMetadata->fieldMappings['number']['quoted']);
304
        $this->assertEquals('phone-number', $phoneMetadata->fieldMappings['number']['columnName']);
305
306
        $user = $phoneMetadata->associationMappings['user'];
307
        $this->assertTrue($user['joinColumns'][0]['quoted']);
308
        $this->assertEquals('user-id', $user['joinColumns'][0]['name']);
309
        $this->assertEquals('user-id', $user['joinColumns'][0]['referencedColumnName']);
310
311
312
313
        // User Group Metadata
314
        $this->assertTrue($groupMetadata->fieldMappings['id']['quoted']);
315
        $this->assertTrue($groupMetadata->fieldMappings['name']['quoted']);
316
317
        $this->assertEquals('user-id', $userMetadata->fieldMappings['id']['columnName']);
318
        $this->assertEquals('user-name', $userMetadata->fieldMappings['name']['columnName']);
319
320
        $user = $groupMetadata->associationMappings['parent'];
321
        $this->assertTrue($user['joinColumns'][0]['quoted']);
322
        $this->assertEquals('parent-id', $user['joinColumns'][0]['name']);
323
        $this->assertEquals('group-id', $user['joinColumns'][0]['referencedColumnName']);
324
325
326
        // Address Class Metadata
327
        $this->assertTrue($addressMetadata->fieldMappings['id']['quoted']);
328
        $this->assertTrue($addressMetadata->fieldMappings['zip']['quoted']);
329
330
        $this->assertEquals('address-id', $addressMetadata->fieldMappings['id']['columnName']);
331
        $this->assertEquals('address-zip', $addressMetadata->fieldMappings['zip']['columnName']);
332
333
        $user = $addressMetadata->associationMappings['user'];
334
        $this->assertTrue($user['joinColumns'][0]['quoted']);
335
        $this->assertEquals('user-id', $user['joinColumns'][0]['name']);
336
        $this->assertEquals('user-id', $user['joinColumns'][0]['referencedColumnName']);
337
338
339
340
        // User Class Metadata
341
        $this->assertTrue($userMetadata->fieldMappings['id']['quoted']);
342
        $this->assertTrue($userMetadata->fieldMappings['name']['quoted']);
343
344
        $this->assertEquals('user-id', $userMetadata->fieldMappings['id']['columnName']);
345
        $this->assertEquals('user-name', $userMetadata->fieldMappings['name']['columnName']);
346
347
348
        $address = $userMetadata->associationMappings['address'];
349
        $this->assertTrue($address['joinColumns'][0]['quoted']);
350
        $this->assertEquals('address-id', $address['joinColumns'][0]['name']);
351
        $this->assertEquals('address-id', $address['joinColumns'][0]['referencedColumnName']);
352
353
        $groups = $userMetadata->associationMappings['groups'];
354
        $this->assertTrue($groups['joinTable']['quoted']);
355
        $this->assertTrue($groups['joinTable']['joinColumns'][0]['quoted']);
356
        $this->assertEquals('quote-users-groups', $groups['joinTable']['name']);
357
        $this->assertEquals('user-id', $groups['joinTable']['joinColumns'][0]['name']);
358
        $this->assertEquals('user-id', $groups['joinTable']['joinColumns'][0]['referencedColumnName']);
359
360
        $this->assertTrue($groups['joinTable']['inverseJoinColumns'][0]['quoted']);
361
        $this->assertEquals('group-id', $groups['joinTable']['inverseJoinColumns'][0]['name']);
362
        $this->assertEquals('group-id', $groups['joinTable']['inverseJoinColumns'][0]['referencedColumnName']);
363
    }
364
365
    /**
366
     * @group DDC-3385
367
     * @group 1181
368
     * @group 385
369
     */
370
    public function testFallbackLoadingCausesEventTriggeringThatCanModifyFetchedMetadata()
371
    {
372
        $test          = $this;
373
        /* @var $metadata \Doctrine\Common\Persistence\Mapping\ClassMetadata */
374
        $metadata      = $this->createMock(ClassMetadata::class);
375
        $cmf           = new ClassMetadataFactory();
376
        $mockDriver    = new MetadataDriverMock();
377
        $em = $this->_createEntityManager($mockDriver);
378
        $listener      = $this->getMockBuilder(\stdClass::class)->setMethods(['onClassMetadataNotFound'])->getMock();
379
        $eventManager  = $em->getEventManager();
380
381
        $cmf->setEntityManager($em);
382
383
        $listener
384
            ->expects($this->any())
385
            ->method('onClassMetadataNotFound')
386
            ->will($this->returnCallback(function (OnClassMetadataNotFoundEventArgs $args) use ($metadata, $em, $test) {
387
                $test->assertNull($args->getFoundMetadata());
388
                $test->assertSame('Foo', $args->getClassName());
389
                $test->assertSame($em, $args->getObjectManager());
390
391
                $args->setFoundMetadata($metadata);
392
            }));
393
394
        $eventManager->addEventListener([Events::onClassMetadataNotFound], $listener);
395
396
        $this->assertSame($metadata, $cmf->getMetadataFor('Foo'));
397
    }
398
399
    /**
400
     * @group DDC-3427
401
     */
402
    public function testAcceptsEntityManagerInterfaceInstances()
403
    {
404
        $classMetadataFactory = new ClassMetadataFactory();
405
406
        /* @var $entityManager EntityManager */
407
        $entityManager        = $this->createMock(EntityManagerInterface::class);
408
409
        $classMetadataFactory->setEntityManager($entityManager);
410
411
        // not really the cleanest way to check it, but we won't add a getter to the CMF just for the sake of testing.
412
        $this->assertAttributeSame($entityManager, 'em', $classMetadataFactory);
413
    }
414
415
    /**
416
     * @group DDC-3305
417
     */
418
    public function testRejectsEmbeddableWithoutValidClassName()
419
    {
420
        $metadata = $this->_createValidClassMetadata();
421
422
        $metadata->mapEmbedded(
423
            [
424
            'fieldName'    => 'embedded',
425
            'class'        => '',
426
            'columnPrefix' => false,
427
            ]
428
        );
429
430
        $cmf = $this->_createTestFactory();
431
432
        $cmf->setMetadataForClass($metadata->name, $metadata);
433
434
        $this->expectException(MappingException::class);
435
        $this->expectExceptionMessage('The embed mapping \'embedded\' misses the \'class\' attribute.');
436
437
        $cmf->getMetadataFor($metadata->name);
438
    }
439
440
    /**
441
     * @group DDC-4006
442
     */
443
    public function testInheritsIdGeneratorMappingFromEmbeddable()
444
    {
445
        $cmf = new ClassMetadataFactory();
446
        $driver = $this->createAnnotationDriver([__DIR__ . '/../../Models/DDC4006/']);
447
        $em = $this->_createEntityManager($driver);
448
        $cmf->setEntityManager($em);
449
450
        $userMetadata = $cmf->getMetadataFor(DDC4006User::class);
451
452
        $this->assertTrue($userMetadata->isIdGeneratorIdentity());
453
    }
454
}
455
456
/* Test subject class with overridden factory method for mocking purposes */
457
class ClassMetadataFactoryTestSubject extends ClassMetadataFactory
458
{
459
    private $mockMetadata = [];
460
    private $requestedClasses = [];
461
462
    /** @override */
463
    protected function newClassMetadataInstance($className)
464
    {
465
        $this->requestedClasses[] = $className;
466
        if ( ! isset($this->mockMetadata[$className])) {
467
            throw new \InvalidArgumentException("No mock metadata found for class $className.");
468
        }
469
        return $this->mockMetadata[$className];
470
    }
471
472
    public function setMetadataForClass($className, $metadata)
473
    {
474
        $this->mockMetadata[$className] = $metadata;
475
    }
476
477
    public function getRequestedClasses()
478
    {
479
        return $this->requestedClasses;
480
    }
481
}
482
483
class TestEntity1
484
{
485
    private $id;
486
    private $name;
487
    private $other;
488
    private $association;
489
    private $embedded;
490
}
491
492
class CustomIdGenerator extends AbstractIdGenerator
493
{
494
    public function generate(EntityManager $em, $entity)
495
    {
496
    }
497
}
498