Failed Conditions
Pull Request — develop (#6684)
by Michael
61:07
created

testGetSingleIdentifierFieldName_NoIdEntity_ThrowsException()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 37 and the first side effect is on line 35.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\ORM\Mapping;
6
7
use Doctrine\DBAL\Types\Type;
8
use Doctrine\ORM\EntityRepository;
9
use Doctrine\ORM\Events;
10
use Doctrine\ORM\Mapping;
11
use Doctrine\ORM\Mapping\ClassMetadata;
12
use Doctrine\ORM\Mapping\DiscriminatorColumnMetadata;
13
use Doctrine\ORM\Mapping\Factory\DefaultNamingStrategy;
14
use Doctrine\ORM\Mapping\Factory\UnderscoreNamingStrategy;
15
use Doctrine\ORM\Mapping\JoinColumnMetadata;
16
use Doctrine\ORM\Mapping\MappingException;
17
use Doctrine\ORM\Reflection\RuntimeReflectionService;
18
use Doctrine\ORM\Reflection\StaticReflectionService;
19
use Doctrine\Tests\Models\CMS;
20
use Doctrine\Tests\Models\Company\CompanyContract;
21
use Doctrine\Tests\Models\Company\CompanyContractListener;
22
use Doctrine\Tests\Models\CustomType\CustomTypeParent;
23
use Doctrine\Tests\Models\DDC117\DDC117Article;
24
use Doctrine\Tests\Models\DDC117\DDC117ArticleDetails;
25
use Doctrine\Tests\Models\DDC6412\DDC6412File;
26
use Doctrine\Tests\Models\DDC964\DDC964Address;
27
use Doctrine\Tests\Models\DDC964\DDC964Admin;
28
use Doctrine\Tests\Models\DDC964\DDC964Guest;
29
use Doctrine\Tests\Models\Routing\RoutingLeg;
30
use Doctrine\Tests\Models\ValueGenerators\DummyWithThreeProperties;
31
use Doctrine\Tests\OrmTestCase;
32
use DoctrineGlobal_Article;
33
use SebastianBergmann\Environment\Runtime;
34
35
require_once __DIR__ . '/../../Models/Global/GlobalNamespaceModel.php';
36
37
class ClassMetadataTest extends OrmTestCase
38
{
39
    /**
40
     * @var Mapping\ClassMetadataBuildingContext|\PHPUnit_Framework_MockObject_MockObject
41
     */
42
    private $metadataBuildingContext;
43
44
    public function setUp()
45
    {
46
        parent::setUp();
47
48
        $this->metadataBuildingContext = new Mapping\ClassMetadataBuildingContext(
49
            $this->createMock(Mapping\ClassMetadataFactory::class),
50
            new RuntimeReflectionService()
51
        );
52
    }
53
54
    public function testClassMetadataInstanceSimpleState()
55
    {
56
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
57
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
58
59
        self::assertInstanceOf(\ReflectionClass::class, $cm->getReflectionClass());
60
        self::assertEquals(CMS\CmsUser::class, $cm->getClassName());
61
        self::assertEquals(CMS\CmsUser::class, $cm->getRootClassName());
62
        self::assertEquals([], $cm->getSubClasses());
63
        self::assertCount(0, $cm->getAncestorsIterator());
64
        self::assertEquals(Mapping\InheritanceType::NONE, $cm->inheritanceType);
65
    }
66
67
    public function testClassMetadataInstanceSerialization()
68
    {
69
        $parent = new ClassMetadata(CMS\CmsEmployee::class, $this->metadataBuildingContext);
70
        $parent->setTable(new Mapping\TableMetadata('cms_employee'));
71
72
        $cm     = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
73
        $cm->setTable($parent->table);
74
        $cm->setParent($parent);
75
76
        $discrColumn = new DiscriminatorColumnMetadata();
77
78
        $discrColumn->setColumnName('disc');
79
        $discrColumn->setType(Type::getType('integer'));
80
81
        $cm->setInheritanceType(Mapping\InheritanceType::SINGLE_TABLE);
82
        $cm->setSubclasses([
83
            'Doctrine\Tests\Models\CMS\One',
84
            'Doctrine\Tests\Models\CMS\Two',
85
            'Doctrine\Tests\Models\CMS\Three'
86
        ]);
87
        $cm->setCustomRepositoryClassName('Doctrine\Tests\Models\CMS\UserRepository');
88
        $cm->setDiscriminatorColumn($discrColumn);
89
        $cm->asReadOnly();
90
        $cm->addNamedQuery('dql', 'foo');
91
92
        $association = new Mapping\OneToOneAssociationMetadata('phonenumbers');
93
94
        $association->setTargetEntity(CMS\CmsAddress::class);
95
        $association->setMappedBy('foo');
96
97
        $cm->addProperty($association);
98
99
        self::assertCount(1, $cm->getDeclaredPropertiesIterator());
100
101
        $serialized = serialize($cm);
102
        $cm = unserialize($serialized);
103
104
        $cm->wakeupReflection(new RuntimeReflectionService());
105
106
        // Check state
107
        self::assertInstanceOf(\ReflectionClass::class, $cm->getReflectionClass());
108
        self::assertEquals(CMS\CmsUser::class, $cm->getClassName());
109
        self::assertEquals(CMS\CmsEmployee::class, $cm->getRootClassName());
110
        self::assertEquals('Doctrine\Tests\Models\CMS\UserRepository', $cm->getCustomRepositoryClassName());
111
        self::assertEquals(
112
            [
113
                'Doctrine\Tests\Models\CMS\One',
114
                'Doctrine\Tests\Models\CMS\Two',
115
                'Doctrine\Tests\Models\CMS\Three'
116
            ],
117
            $cm->getSubClasses()
118
        );
119
        self::assertCount(1, $cm->getAncestorsIterator());
120
        self::assertEquals(CMS\CmsEmployee::class, $cm->getAncestorsIterator()->current()->getClassName());
121
        self::assertEquals($discrColumn, $cm->discriminatorColumn);
122
        self::assertTrue($cm->isReadOnly());
123
        self::assertEquals(['dql' => 'foo'], $cm->getNamedQueries());
124
        self::assertCount(1, $cm->getDeclaredPropertiesIterator());
125
        self::assertInstanceOf(Mapping\OneToOneAssociationMetadata::class, $cm->getProperty('phonenumbers'));
126
127
        $oneOneMapping = $cm->getProperty('phonenumbers');
128
129
        self::assertEquals(Mapping\FetchMode::LAZY, $oneOneMapping->getFetchMode());
130
        self::assertEquals(CMS\CmsAddress::class, $oneOneMapping->getTargetEntity());
131
    }
132
133
    public function testFieldIsNullable()
134
    {
135
        $metadata = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
136
        $metadata->setTable(new Mapping\TableMetadata('cms_users'));
137
138
        // Explicit Nullable
139
        $fieldMetadata = new Mapping\FieldMetadata('status');
140
141
        $fieldMetadata->setType(Type::getType('string'));
142
        $fieldMetadata->setLength(50);
143
        $fieldMetadata->setNullable(true);
144
145
        $metadata->addProperty($fieldMetadata);
146
147
        $property = $metadata->getProperty('status');
148
149
        self::assertTrue($property->isNullable());
150
151
        // Explicit Not Nullable
152
        $fieldMetadata = new Mapping\FieldMetadata('username');
153
154
        $fieldMetadata->setType(Type::getType('string'));
155
        $fieldMetadata->setLength(50);
156
        $fieldMetadata->setNullable(false);
157
158
        $metadata->addProperty($fieldMetadata);
159
160
        $property = $metadata->getProperty('username');
161
162
        self::assertFalse($property->isNullable());
163
164
        // Implicit Not Nullable
165
        $fieldMetadata = new Mapping\FieldMetadata('name');
166
167
        $fieldMetadata->setType(Type::getType('string'));
168
        $fieldMetadata->setLength(50);
169
170
        $metadata->addProperty($fieldMetadata);
171
172
        $property = $metadata->getProperty('name');
173
174
        self::assertFalse($property->isNullable(), "By default a field should not be nullable.");
175
    }
176
177
    /**
178
     * @group DDC-115
179
     */
180
    public function testMapAssociationInGlobalNamespace()
181
    {
182
        require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php";
183
184
        $cm = new ClassMetadata(DoctrineGlobal_Article::class, $this->metadataBuildingContext);
185
        $cm->setTable(new Mapping\TableMetadata('doctrine_global_article'));
186
187
        $joinTable = new Mapping\JoinTableMetadata();
188
        $joinTable->setName('bar');
189
190
        $joinColumn = new Mapping\JoinColumnMetadata();
191
        $joinColumn->setColumnName("bar_id");
192
        $joinColumn->setReferencedColumnName("id");
193
194
        $joinTable->addJoinColumn($joinColumn);
195
196
        $joinColumn = new Mapping\JoinColumnMetadata();
197
        $joinColumn->setColumnName("baz_id");
198
        $joinColumn->setReferencedColumnName("id");
199
200
        $joinTable->addInverseJoinColumn($joinColumn);
201
202
        $association = new Mapping\ManyToManyAssociationMetadata('author');
203
204
        $association->setJoinTable($joinTable);
205
        $association->setTargetEntity('DoctrineGlobal_User');
206
207
        $cm->addProperty($association);
208
209
        self::assertEquals("DoctrineGlobal_User", $cm->getProperty('author')->getTargetEntity());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\ORM\Mapping\Property as the method getTargetEntity() does only exist in the following implementations of said interface: Doctrine\ORM\Mapping\AssociationMetadata, Doctrine\ORM\Mapping\ManyToManyAssociationMetadata, Doctrine\ORM\Mapping\ManyToOneAssociationMetadata, Doctrine\ORM\Mapping\OneToManyAssociationMetadata, Doctrine\ORM\Mapping\OneToOneAssociationMetadata, Doctrine\ORM\Mapping\ToManyAssociationMetadata, Doctrine\ORM\Mapping\ToOneAssociationMetadata.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
210
    }
211
212 View Code Duplication
    public function testMapManyToManyJoinTableDefaults()
213
    {
214
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
215
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
216
217
        $association = new Mapping\ManyToManyAssociationMetadata('groups');
218
219
        $association->setTargetEntity(CMS\CmsGroup::class);
220
221
        $cm->addProperty($association);
222
223
        $association = $cm->getProperty('groups');
224
225
        $joinColumns = [];
226
227
        $joinColumn = new Mapping\JoinColumnMetadata();
228
229
        $joinColumn->setColumnName("cmsuser_id");
230
        $joinColumn->setReferencedColumnName("id");
231
        $joinColumn->setOnDelete("CASCADE");
232
233
        $joinColumns[] = $joinColumn;
234
235
        $inverseJoinColumns = [];
236
237
        $joinColumn = new Mapping\JoinColumnMetadata();
238
239
        $joinColumn->setColumnName("cmsgroup_id");
240
        $joinColumn->setReferencedColumnName("id");
241
        $joinColumn->setOnDelete("CASCADE");
242
243
        $inverseJoinColumns[] = $joinColumn;
244
245
        $joinTable = $association->getJoinTable();
246
247
        self::assertEquals('cmsuser_cmsgroup', $joinTable->getName());
248
        self::assertEquals($joinColumns, $joinTable->getJoinColumns());
249
        self::assertEquals($inverseJoinColumns, $joinTable->getInverseJoinColumns());
250
    }
251
252
    public function testSerializeManyToManyJoinTableCascade()
253
    {
254
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
255
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
256
257
        $association = new Mapping\ManyToManyAssociationMetadata('groups');
258
259
        $association->setTargetEntity(CMS\CmsGroup::class);
260
261
        $cm->addProperty($association);
262
263
        $association = $cm->getProperty('groups');
264
        $association = unserialize(serialize($association));
265
266
        $joinTable = $association->getJoinTable();
267
268
        foreach ($joinTable->getJoinColumns() as $joinColumn) {
269
            self::assertEquals('CASCADE', $joinColumn->getOnDelete());
270
        }
271
    }
272
273
    /**
274
     * @group DDC-115
275
     */
276
    public function testSetDiscriminatorMapInGlobalNamespace()
277
    {
278
        require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php";
279
280
        $cm = new ClassMetadata('DoctrineGlobal_User', $this->metadataBuildingContext);
281
        $cm->setTable(new Mapping\TableMetadata('doctrine_global_user'));
282
283
        $cm->setDiscriminatorMap(['descr' => 'DoctrineGlobal_Article', 'foo' => 'DoctrineGlobal_User']);
284
285
        self::assertEquals("DoctrineGlobal_Article", $cm->discriminatorMap['descr']);
286
        self::assertEquals("DoctrineGlobal_User", $cm->discriminatorMap['foo']);
287
    }
288
289
    /**
290
     * @group DDC-115
291
     */
292
    public function testSetSubClassesInGlobalNamespace()
293
    {
294
        require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php";
295
296
        $cm = new ClassMetadata('DoctrineGlobal_User', $this->metadataBuildingContext);
297
        $cm->setTable(new Mapping\TableMetadata('doctrine_global_user'));
298
299
        $cm->setSubclasses(['DoctrineGlobal_Article']);
300
301
        self::assertEquals("DoctrineGlobal_Article", $cm->getSubClasses()[0]);
302
    }
303
304
    /**
305
     * @group DDC-268
306
     */
307 View Code Duplication
    public function testSetInvalidVersionMapping_ThrowsException()
308
    {
309
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
310
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
311
312
        $property = new Mapping\VersionFieldMetadata('foo');
313
314
        $property->setDeclaringClass($cm);
315
        $property->setColumnName('foo');
316
        $property->setType(Type::getType('string'));
317
318
        $this->expectException(MappingException::class);
319
320
        $cm->addProperty($property);
321
    }
322
323
    public function testGetSingleIdentifierFieldName_MultipleIdentifierEntity_ThrowsException()
324
    {
325
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
326
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
327
328
        $fieldMetadata = new Mapping\FieldMetadata('name');
329
        $fieldMetadata->setType(Type::getType('string'));
330
331
        $cm->addProperty($fieldMetadata);
332
333
        $fieldMetadata = new Mapping\FieldMetadata('username');
334
        $fieldMetadata->setType(Type::getType('string'));
335
336
        $cm->addProperty($fieldMetadata);
337
338
        $cm->setIdentifier(['name', 'username']);
339
340
        $this->expectException(MappingException::class);
341
342
        $cm->getSingleIdentifierFieldName();
343
    }
344
345
    public function testGetSingleIdentifierFieldName_NoIdEntity_ThrowsException()
346
    {
347
        $cm = new ClassMetadata(DDC6412File::class, $this->metadataBuildingContext);
348
        $cm->setTable(new Mapping\TableMetadata('ddc6412_file'));
349
350
        $this->expectException(\Doctrine\ORM\Mapping\MappingException::class);
351
352
        $cm->getSingleIdentifierFieldName();
353
    }
354
355
    public function testDuplicateAssociationMappingException()
356
    {
357
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
358
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
359
360
        $association = new Mapping\OneToOneAssociationMetadata('foo');
361
362
        $association->setDeclaringClass($cm);
363
        $association->setSourceEntity(\stdClass::class);
364
        $association->setTargetEntity(\stdClass::class);
365
        $association->setMappedBy('foo');
366
367
        $cm->addInheritedProperty($association);
368
369
        $this->expectException(MappingException::class);
370
371
        $association = new Mapping\OneToOneAssociationMetadata('foo');
372
373
        $association->setDeclaringClass($cm);
374
        $association->setSourceEntity(\stdClass::class);
375
        $association->setTargetEntity(\stdClass::class);
376
        $association->setMappedBy('foo');
377
378
        $cm->addInheritedProperty($association);
379
    }
380
381
    public function testDuplicateColumnName_ThrowsMappingException()
382
    {
383
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
384
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
385
386
        $fieldMetadata = new Mapping\FieldMetadata('name');
387
388
        $fieldMetadata->setType(Type::getType('string'));
389
390
        $cm->addProperty($fieldMetadata);
391
392
        $this->expectException(MappingException::class);
393
394
        $fieldMetadata = new Mapping\FieldMetadata('username');
395
396
        $fieldMetadata->setType(Type::getType('string'));
397
        $fieldMetadata->setColumnName('name');
398
399
        $cm->addProperty($fieldMetadata);
400
    }
401
402
    public function testDuplicateColumnName_DiscriminatorColumn_ThrowsMappingException()
403
    {
404
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
405
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
406
407
        $fieldMetadata = new Mapping\FieldMetadata('name');
408
409
        $fieldMetadata->setType(Type::getType('string'));
410
411
        $cm->addProperty($fieldMetadata);
412
413
        $discrColumn = new DiscriminatorColumnMetadata();
414
415
        $discrColumn->setColumnName('name');
416
        $discrColumn->setType(Type::getType('string'));
417
        $discrColumn->setLength(255);
418
419
        $this->expectException(\Doctrine\ORM\Mapping\MappingException::class);
420
421
        $cm->setDiscriminatorColumn($discrColumn);
422
    }
423
424
    public function testDuplicateColumnName_DiscriminatorColumn2_ThrowsMappingException()
425
    {
426
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
427
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
428
429
        $discrColumn = new DiscriminatorColumnMetadata();
430
431
        $discrColumn->setColumnName('name');
432
        $discrColumn->setType(Type::getType('string'));
433
        $discrColumn->setLength(255);
434
435
        $cm->setDiscriminatorColumn($discrColumn);
436
437
        $this->expectException(\Doctrine\ORM\Mapping\MappingException::class);
438
439
        $fieldMetadata = new Mapping\FieldMetadata('name');
440
441
        $fieldMetadata->setType(Type::getType('string'));
442
443
        $cm->addProperty($fieldMetadata);
444
    }
445
446
    public function testDuplicateFieldAndAssociationMapping1_ThrowsException()
447
    {
448
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
449
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
450
451
        $fieldMetadata = new Mapping\FieldMetadata('name');
452
453
        $fieldMetadata->setType(Type::getType('string'));
454
455
        $cm->addProperty($fieldMetadata);
456
457
        $this->expectException(\Doctrine\ORM\Mapping\MappingException::class);
458
459
        $association = new Mapping\OneToOneAssociationMetadata('name');
460
461
        $association->setTargetEntity(CMS\CmsUser::class);
462
463
        $cm->addProperty($association);
464
    }
465
466
    public function testDuplicateFieldAndAssociationMapping2_ThrowsException()
467
    {
468
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
469
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
470
471
        $association = new Mapping\OneToOneAssociationMetadata('name');
472
473
        $association->setTargetEntity(CMS\CmsUser::class);
474
475
        $cm->addProperty($association);
476
477
        $this->expectException(\Doctrine\ORM\Mapping\MappingException::class);
478
479
        $fieldMetadata = new Mapping\FieldMetadata('name');
480
481
        $fieldMetadata->setType(Type::getType('string'));
482
483
        $cm->addProperty($fieldMetadata);
484
    }
485
486
    /**
487
     * @group DDC-1224
488
     */
489 View Code Duplication
    public function testGetTemporaryTableNameSchema()
490
    {
491
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
492
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
493
494
        $tableMetadata = new Mapping\TableMetadata();
495
496
        $tableMetadata->setSchema('foo');
497
        $tableMetadata->setName('bar');
498
499
        $cm->setTable($tableMetadata);
500
501
        self::assertEquals('foo_bar_id_tmp', $cm->getTemporaryIdTableName());
502
    }
503
504
    public function testDefaultTableName()
505
    {
506
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
507
        $cm->setTable(new Mapping\TableMetadata('CmsUser'));
508
509
        // When table's name is not given
510
        self::assertEquals('CmsUser', $cm->getTableName());
511
        self::assertEquals('CmsUser', $cm->table->getName());
512
513
        $cm = new ClassMetadata(CMS\CmsAddress::class, $this->metadataBuildingContext);
514
515
        // When joinTable's name is not given
516
        $joinTable = new Mapping\JoinTableMetadata();
517
518
        $joinColumn = new Mapping\JoinColumnMetadata();
519
        $joinColumn->setReferencedColumnName("id");
520
521
        $joinTable->addJoinColumn($joinColumn);
522
523
        $joinColumn = new Mapping\JoinColumnMetadata();
524
        $joinColumn->setReferencedColumnName("id");
525
526
        $joinTable->addInverseJoinColumn($joinColumn);
527
528
        $association = new Mapping\ManyToManyAssociationMetadata('user');
529
530
        $association->setJoinTable($joinTable);
531
        $association->setTargetEntity(CMS\CmsUser::class);
532
        $association->setInversedBy('users');
533
534
        $cm->addProperty($association);
535
536
        $association = $cm->getProperty('user');
537
538
        self::assertEquals('cmsaddress_cmsuser', $association->getJoinTable()->getName());
539
    }
540
541
    public function testDefaultJoinColumnName()
542
    {
543
        $cm = new ClassMetadata(CMS\CmsAddress::class, $this->metadataBuildingContext);
544
        $cm->setTable(new Mapping\TableMetadata('cms_address'));
545
546
        // this is really dirty, but it's the simplest way to test whether
547
        // joinColumn's name will be automatically set to user_id
548
        $joinColumns = [];
549
550
        $joinColumn = new JoinColumnMetadata();
551
552
        $joinColumn->setReferencedColumnName('id');
553
554
        $joinColumns[] = $joinColumn;
555
556
        $association = new Mapping\OneToOneAssociationMetadata('user');
557
558
        $association->setJoinColumns($joinColumns);
559
        $association->setTargetEntity(CMS\CmsUser::class);
560
561
        $cm->addProperty($association);
562
563
        $association = $cm->getProperty('user');
564
        $joinColumns = $association->getJoinColumns();
565
        $joinColumn  = reset($joinColumns);
566
567
        self::assertEquals('user_id', $joinColumn->getColumnName());
568
569
        $cm = new ClassMetadata(CMS\CmsAddress::class, $this->metadataBuildingContext);
570
        $cm->setTable(new Mapping\TableMetadata('cms_address'));
571
572
        $joinTable = new Mapping\JoinTableMetadata();
573
        $joinTable->setName('user_CmsUser');
574
575
        $joinColumn = new JoinColumnMetadata();
576
        $joinColumn->setReferencedColumnName('id');
577
578
        $joinTable->addJoinColumn($joinColumn);
579
580
        $joinColumn = new JoinColumnMetadata();
581
        $joinColumn->setReferencedColumnName('id');
582
583
        $joinTable->addInverseJoinColumn($joinColumn);
584
585
        $association = new Mapping\ManyToManyAssociationMetadata('user');
586
587
        $association->setJoinTable($joinTable);
588
        $association->setTargetEntity(CMS\CmsUser::class);
589
        $association->setInversedBy('users');
590
591
        $cm->addProperty($association);
592
593
        $association        = $cm->getProperty('user');
594
        $joinTable          = $association->getJoinTable();
595
        $joinColumns        = $joinTable->getJoinColumns();
596
        $joinColumn         = reset($joinColumns);
597
        $inverseJoinColumns = $joinTable->getInverseJoinColumns();
598
        $inverseJoinColumn  = reset($inverseJoinColumns);
599
600
        self::assertEquals('cmsaddress_id', $joinColumn->getColumnName());
601
        self::assertEquals('cmsuser_id', $inverseJoinColumn->getColumnName());
602
    }
603
604
    /**
605
     * @group DDC-559
606
     */
607
    public function testOneToOneUnderscoreNamingStrategyDefaults()
608
    {
609
        $namingStrategy = new UnderscoreNamingStrategy(CASE_UPPER);
610
611
        $this->metadataBuildingContext = new Mapping\ClassMetadataBuildingContext(
612
            $this->createMock(Mapping\ClassMetadataFactory::class),
613
            new RuntimeReflectionService(),
614
            $namingStrategy
615
        );
616
617
        $metadata = new ClassMetadata(CMS\CmsAddress::class, $this->metadataBuildingContext);
618
        $metadata->setTable(new Mapping\TableMetadata('cms_address'));
619
620
        $association = new Mapping\OneToOneAssociationMetadata('user');
621
622
        $association->setTargetEntity(CMS\CmsUser::class);
623
624
        $metadata->addProperty($association);
625
626
        $association = $metadata->getProperty('user');
627
        $joinColumns = $association->getJoinColumns();
628
        $joinColumn  = reset($joinColumns);
629
630
        self::assertEquals('USER_ID', $joinColumn->getColumnName());
631
        self::assertEquals('ID', $joinColumn->getReferencedColumnName());
632
    }
633
634
    /**
635
     * @group DDC-559
636
     */
637
    public function testManyToManyUnderscoreNamingStrategyDefaults()
638
    {
639
        $namingStrategy = new UnderscoreNamingStrategy(CASE_UPPER);
640
641
        $this->metadataBuildingContext = new Mapping\ClassMetadataBuildingContext(
642
            $this->createMock(Mapping\ClassMetadataFactory::class),
643
            new RuntimeReflectionService(),
644
            $namingStrategy
645
        );
646
647
        $metadata = new ClassMetadata(CMS\CmsAddress::class, $this->metadataBuildingContext);
648
        $metadata->setTable(new Mapping\TableMetadata('cms_address'));
649
650
        $association = new Mapping\ManyToManyAssociationMetadata('user');
651
652
        $association->setTargetEntity(CMS\CmsUser::class);
653
654
        $metadata->addProperty($association);
655
656
        $association        = $metadata->getProperty('user');
657
        $joinTable          = $association->getJoinTable();
658
        $joinColumns        = $joinTable->getJoinColumns();
659
        $joinColumn         = reset($joinColumns);
660
        $inverseJoinColumns = $joinTable->getInverseJoinColumns();
661
        $inverseJoinColumn  = reset($inverseJoinColumns);
662
663
        self::assertEquals('CMS_ADDRESS_CMS_USER', $joinTable->getName());
664
665
        self::assertEquals('CMS_ADDRESS_ID', $joinColumn->getColumnName());
666
        self::assertEquals('ID', $joinColumn->getReferencedColumnName());
667
668
        self::assertEquals('CMS_USER_ID', $inverseJoinColumn->getColumnName());
669
        self::assertEquals('ID', $inverseJoinColumn->getReferencedColumnName());
670
671
        $cm = new ClassMetadata('DoctrineGlobal_Article', $this->metadataBuildingContext);
672
673
        $association = new Mapping\ManyToManyAssociationMetadata('author');
674
675
        $association->setTargetEntity(CMS\CmsUser::class);
676
677
        $cm->addProperty($association);
678
679
        $association = $cm->getProperty('author');
680
681
        self::assertEquals('DOCTRINE_GLOBAL_ARTICLE_CMS_USER', $association->getJoinTable()->getName());
682
    }
683
684
    /**
685
     * @group DDC-886
686
     */
687
    public function testSetMultipleIdentifierSetsComposite()
688
    {
689
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
690
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
691
692
        $fieldMetadata = new Mapping\FieldMetadata('name');
693
        $fieldMetadata->setType(Type::getType('string'));
694
695
        $cm->addProperty($fieldMetadata);
696
697
        $fieldMetadata = new Mapping\FieldMetadata('username');
698
        $fieldMetadata->setType(Type::getType('string'));
699
700
        $cm->addProperty($fieldMetadata);
701
702
        $cm->setIdentifier(['name', 'username']);
703
704
        self::assertTrue($cm->isIdentifierComposite());
705
    }
706
707
    /**
708
     * @group DDC-961
709
     */
710
    public function testJoinTableMappingDefaults()
711
    {
712
        $cm = new ClassMetadata('DoctrineGlobal_Article', $this->metadataBuildingContext);
713
714
        $association = new Mapping\ManyToManyAssociationMetadata('author');
715
716
        $association->setTargetEntity(CMS\CmsUser::class);
717
718
        $cm->addProperty($association);
719
720
        $association = $cm->getProperty('author');
721
722
        self::assertEquals('doctrineglobal_article_cmsuser', $association->getJoinTable()->getName());
723
    }
724
725
    /**
726
     * @group DDC-117
727
     */
728
    public function testMapIdentifierAssociation()
729
    {
730
        $cm = new ClassMetadata(DDC117ArticleDetails::class, $this->metadataBuildingContext);
731
        $cm->setTable(new Mapping\TableMetadata("ddc117_article_details"));
732
733
        $association = new Mapping\OneToOneAssociationMetadata('article');
734
735
        $association->setTargetEntity(DDC117Article::class);
736
        $association->setPrimaryKey(true);
737
738
        $cm->addProperty($association);
739
740
        self::assertEquals(["article"], $cm->identifier);
741
    }
742
743
    /**
744
     * @group DDC-117
745
     */
746 View Code Duplication
    public function testOrphanRemovalIdentifierAssociation()
747
    {
748
        $cm = new ClassMetadata(DDC117ArticleDetails::class, $this->metadataBuildingContext);
749
        $cm->setTable(new Mapping\TableMetadata("ddc117_article_details"));
750
751
        $this->expectException(MappingException::class);
752
        $this->expectExceptionMessage('The orphan removal option is not allowed on an association that');
753
754
        $association = new Mapping\OneToOneAssociationMetadata('article');
755
756
        $association->setTargetEntity(DDC117Article::class);
757
        $association->setPrimaryKey(true);
758
        $association->setOrphanRemoval(true);
759
760
        $cm->addProperty($association);
761
    }
762
763
    /**
764
     * @group DDC-117
765
     */
766 View Code Duplication
    public function testInverseIdentifierAssociation()
767
    {
768
        $cm = new ClassMetadata(DDC117ArticleDetails::class, $this->metadataBuildingContext);
769
        $cm->setTable(new Mapping\TableMetadata("ddc117_article_details"));
770
771
        $this->expectException(MappingException::class);
772
        $this->expectExceptionMessage('An inverse association is not allowed to be identifier in');
773
774
        $association = new Mapping\OneToOneAssociationMetadata('article');
775
776
        $association->setTargetEntity(DDC117Article::class);
777
        $association->setPrimaryKey(true);
778
        $association->setMappedBy('details');
779
780
        $cm->addProperty($association);
781
    }
782
783
    /**
784
     * @group DDC-117
785
     */
786 View Code Duplication
    public function testIdentifierAssociationManyToMany()
787
    {
788
        $cm = new ClassMetadata(DDC117ArticleDetails::class, $this->metadataBuildingContext);
789
        $cm->setTable(new Mapping\TableMetadata("ddc117_article_details"));
790
791
        $this->expectException(MappingException::class);
792
        $this->expectExceptionMessage('Many-to-many or one-to-many associations are not allowed to be identifier in');
793
794
        $association = new Mapping\ManyToManyAssociationMetadata('article');
795
796
        $association->setTargetEntity(DDC117Article::class);
797
        $association->setPrimaryKey(true);
798
799
        $cm->addProperty($association);
800
    }
801
802
    /**
803
     * @group DDC-996
804
     */
805 View Code Duplication
    public function testEmptyFieldNameThrowsException()
806
    {
807
        $this->expectException(MappingException::class);
808
        $this->expectExceptionMessage("The field or association mapping misses the 'fieldName' attribute in entity '" . CMS\CmsUser::class . "'.");
809
810
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
811
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
812
813
        $fieldMetadata = new Mapping\FieldMetadata('');
814
815
        $fieldMetadata->setType(Type::getType('string'));
816
817
        $cm->addProperty($fieldMetadata);
818
    }
819
820 View Code Duplication
    public function testRetrievalOfNamedQueries()
821
    {
822
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
823
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
824
825
        self::assertEquals(0, count($cm->getNamedQueries()));
826
827
        $cm->addNamedQuery('userById', 'SELECT u FROM __CLASS__ u WHERE u.id = ?1');
828
829
        self::assertEquals(1, count($cm->getNamedQueries()));
830
    }
831
832
    /**
833
     * @group DDC-1663
834
     */
835 View Code Duplication
    public function testRetrievalOfResultSetMappings()
836
    {
837
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
838
839
        self::assertEquals(0, count($cm->getSqlResultSetMappings()));
840
841
        $cm->addSqlResultSetMapping(
842
            [
843
            'name'      => 'find-all',
844
            'entities'  => [
845
                [
846
                    'entityClass'   => CMS\CmsUser::class,
847
                ],
848
            ],
849
            ]
850
        );
851
852
        self::assertEquals(1, count($cm->getSqlResultSetMappings()));
853
    }
854
855
    public function testExistanceOfNamedQuery()
856
    {
857
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
858
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
859
860
        $cm->addNamedQuery('all', 'SELECT u FROM __CLASS__ u');
861
862
        self::assertTrue($cm->hasNamedQuery('all'));
863
        self::assertFalse($cm->hasNamedQuery('userById'));
864
    }
865
866
    /**
867
     * @group DDC-1663
868
     */
869
    public function testRetrieveOfNamedNativeQuery()
870
    {
871
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
872
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
873
874
        $cm->addNamedNativeQuery(
875
            'find-all',
876
            'SELECT * FROM cms_users',
877
            [
878
                'resultSetMapping' => 'result-mapping-name',
879
                'resultClass'      => CMS\CmsUser::class,
880
            ]
881
        );
882
883
        $cm->addNamedNativeQuery(
884
            'find-by-id',
885
            'SELECT * FROM cms_users WHERE id = ?',
886
            [
887
                'resultClass'      => '__CLASS__',
888
                'resultSetMapping' => 'result-mapping-name',
889
            ]
890
        );
891
892
        $mapping = $cm->getNamedNativeQuery('find-all');
893
894
        self::assertEquals('SELECT * FROM cms_users', $mapping['query']);
895
        self::assertEquals('result-mapping-name', $mapping['resultSetMapping']);
896
        self::assertEquals(CMS\CmsUser::class, $mapping['resultClass']);
897
898
        $mapping = $cm->getNamedNativeQuery('find-by-id');
899
900
        self::assertEquals('SELECT * FROM cms_users WHERE id = ?', $mapping['query']);
901
        self::assertEquals('result-mapping-name', $mapping['resultSetMapping']);
902
        self::assertEquals('__CLASS__', $mapping['resultClass']);
903
    }
904
905
    /**
906
     * @group DDC-1663
907
     */
908
    public function testRetrieveOfSqlResultSetMapping()
909
    {
910
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
911
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
912
913
        $cm->addSqlResultSetMapping(
914
            [
915
                'name'      => 'find-all',
916
                'entities'  => [
917
                    [
918
                        'entityClass'   => '__CLASS__',
919
                        'fields'        => [
920
                            [
921
                                'name'  => 'id',
922
                                'column'=> 'id'
923
                            ],
924
                            [
925
                                'name'  => 'name',
926
                                'column'=> 'name'
927
                            ]
928
                        ]
929
                    ],
930
                    [
931
                        'entityClass'   => CMS\CmsEmail::class,
932
                        'fields'        => [
933
                            [
934
                                'name'  => 'id',
935
                                'column'=> 'id'
936
                            ],
937
                            [
938
                                'name'  => 'email',
939
                                'column'=> 'email'
940
                            ]
941
                        ]
942
                    ]
943
                ],
944
                'columns'   => [['name' => 'scalarColumn']]
945
            ]
946
        );
947
948
        $mapping = $cm->getSqlResultSetMapping('find-all');
949
950
        self::assertEquals('__CLASS__', $mapping['entities'][0]['entityClass']);
951
        self::assertEquals(['name'=>'id','column'=>'id'], $mapping['entities'][0]['fields'][0]);
952
        self::assertEquals(['name'=>'name','column'=>'name'], $mapping['entities'][0]['fields'][1]);
953
954
        self::assertEquals(CMS\CmsEmail::class, $mapping['entities'][1]['entityClass']);
955
        self::assertEquals(['name'=>'id','column'=>'id'], $mapping['entities'][1]['fields'][0]);
956
        self::assertEquals(['name'=>'email','column'=>'email'], $mapping['entities'][1]['fields'][1]);
957
958
        self::assertEquals('scalarColumn', $mapping['columns'][0]['name']);
959
    }
960
961
    /**
962
     * @expectedException \Doctrine\ORM\Mapping\MappingException
963
     * @expectedExceptionMessage Entity 'Doctrine\Tests\Models\ValueGenerators\DummyWithThreeProperties' has a composite identifier with with an Identity strategy. This is not supported.
964
     */
965 View Code Duplication
    public function testCompositeIdentifierWithIdentityValueGenerator() : void
966
    {
967
        $classMetadata = new ClassMetadata(DummyWithThreeProperties::class, $this->metadataBuildingContext);
968
        $classMetadata->setTable(new Mapping\TableMetadata());
969
970
        $fooMetadata = new Mapping\FieldMetadata('a');
971
        $fooMetadata->setType(Type::getType(Type::INTEGER));
972
        $fooMetadata->setPrimaryKey(true);
973
        $fooMetadata->setValueGenerator(new Mapping\ValueGeneratorMetadata(Mapping\GeneratorType::NONE));
974
        $classMetadata->addProperty($fooMetadata);
975
976
        $barMetadata = new Mapping\FieldMetadata('b');
977
        $barMetadata->setType(Type::getType(Type::INTEGER));
978
        $barMetadata->setPrimaryKey(true);
979
        $barMetadata->setValueGenerator(new Mapping\ValueGeneratorMetadata(Mapping\GeneratorType::IDENTITY));
980
        $classMetadata->addProperty($barMetadata);
981
982
        $classMetadata->validateValueGenerators();
983
    }
984
985
    /**
986
     * @expectedException \Doctrine\ORM\Mapping\MappingException
987
     * @expectedExceptionMessage Entity 'Doctrine\Tests\Models\ValueGenerators\DummyWithThreeProperties' has a an Identity strategy defined on a non-primary field. This is not supported.
988
     */
989 View Code Duplication
    public function testNonPrimaryIdentityValueGenerator() : void
990
    {
991
        $classMetadata = new ClassMetadata(DummyWithThreeProperties::class, $this->metadataBuildingContext);
992
        $classMetadata->setTable(new Mapping\TableMetadata());
993
994
        $fooMetadata = new Mapping\FieldMetadata('a');
995
        $fooMetadata->setType(Type::getType(Type::INTEGER));
996
        $fooMetadata->setPrimaryKey(true);
997
        $fooMetadata->setValueGenerator(new Mapping\ValueGeneratorMetadata(Mapping\GeneratorType::NONE));
998
        $classMetadata->addProperty($fooMetadata);
999
1000
        $barMetadata = new Mapping\FieldMetadata('b');
1001
        $barMetadata->setType(Type::getType(Type::INTEGER));
1002
        $barMetadata->setPrimaryKey(false);
1003
        $barMetadata->setValueGenerator(new Mapping\ValueGeneratorMetadata(Mapping\GeneratorType::IDENTITY));
1004
        $classMetadata->addProperty($barMetadata);
1005
1006
        $classMetadata->validateValueGenerators();
1007
    }
1008
1009
    /**
1010
     * @group DDC-1663
1011
     */
1012 View Code Duplication
    public function testExistanceOfSqlResultSetMapping()
1013
    {
1014
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1015
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1016
1017
        $cm->addSqlResultSetMapping(
1018
            [
1019
                'name'      => 'find-all',
1020
                'entities'  => [
1021
                    [
1022
                        'entityClass'   => CMS\CmsUser::class,
1023
                    ],
1024
                ],
1025
            ]
1026
        );
1027
1028
        self::assertTrue($cm->hasSqlResultSetMapping('find-all'));
1029
        self::assertFalse($cm->hasSqlResultSetMapping('find-by-id'));
1030
    }
1031
1032
    /**
1033
     * @group DDC-1663
1034
     */
1035 View Code Duplication
    public function testExistanceOfNamedNativeQuery()
1036
    {
1037
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1038
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1039
1040
        $cm->addNamedNativeQuery(
1041
            'find-all',
1042
            'SELECT * FROM cms_users',
1043
            [
1044
                'resultClass' => CMS\CmsUser::class,
1045
            ]
1046
        );
1047
1048
        self::assertTrue($cm->hasNamedNativeQuery('find-all'));
1049
        self::assertFalse($cm->hasNamedNativeQuery('find-by-id'));
1050
    }
1051
1052
    public function testRetrieveOfNamedQuery()
1053
    {
1054
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1055
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1056
1057
        $cm->addNamedQuery('userById', 'SELECT u FROM __CLASS__ u WHERE u.id = ?1');
1058
1059
        self::assertEquals('SELECT u FROM __CLASS__ u WHERE u.id = ?1', $cm->getNamedQuery('userById'));
1060
1061
        // Named queries are only resolved when created
1062
        $repo = new EntityRepository($this->getTestEntityManager(), $cm);
1063
1064
        self::assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1', $repo->createNamedQuery('userById')->getDQL());
1065
    }
1066
1067
    /**
1068
     * @group DDC-1663
1069
     */
1070 View Code Duplication
    public function testRetrievalOfNamedNativeQueries()
1071
    {
1072
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1073
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1074
1075
        self::assertEquals(0, count($cm->getNamedNativeQueries()));
1076
1077
        $cm->addNamedNativeQuery(
1078
            'find-all',
1079
            'SELECT * FROM cms_users',
1080
            [
1081
                'resultClass' => CMS\CmsUser::class,
1082
            ]
1083
        );
1084
1085
        self::assertEquals(1, count($cm->getNamedNativeQueries()));
1086
    }
1087
1088
    /**
1089
     * @group DDC-2451
1090
     */
1091
    public function testSerializeEntityListeners()
1092
    {
1093
        $metadata = new ClassMetadata(CompanyContract::class, $this->metadataBuildingContext);
1094
1095
        $metadata->addEntityListener(Events::prePersist, CompanyContractListener::class, 'prePersistHandler');
1096
        $metadata->addEntityListener(Events::postPersist, CompanyContractListener::class, 'postPersistHandler');
1097
1098
        $serialize   = serialize($metadata);
1099
        $unserialize = unserialize($serialize);
1100
1101
        self::assertEquals($metadata->entityListeners, $unserialize->entityListeners);
1102
    }
1103
1104
    /**
1105
     * @expectedException \Doctrine\ORM\Mapping\MappingException
1106
     * @expectedExceptionMessage Query named "userById" in "Doctrine\Tests\Models\CMS\CmsUser" was already declared, but it must be declared only once
1107
     */
1108
    public function testNamingCollisionNamedQueryShouldThrowException()
1109
    {
1110
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1111
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1112
1113
        $cm->addNamedQuery('userById', 'SELECT u FROM __CLASS__ u WHERE u.id = ?1');
1114
        $cm->addNamedQuery('userById', 'SELECT u FROM __CLASS__ u WHERE u.id = ?1');
1115
    }
1116
1117
    /**
1118
     * @group DDC-1663
1119
     *
1120
     * @expectedException \Doctrine\ORM\Mapping\MappingException
1121
     * @expectedExceptionMessage Query named "find-all" in "Doctrine\Tests\Models\CMS\CmsUser" was already declared, but it must be declared only once
1122
     */
1123
    public function testNamingCollisionNamedNativeQueryShouldThrowException()
1124
    {
1125
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1126
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1127
1128
        $cm->addNamedNativeQuery(
1129
            'find-all',
1130
            'SELECT * FROM cms_users',
1131
            [
1132
                'resultClass' => CMS\CmsUser::class,
1133
            ]
1134
        );
1135
1136
        $cm->addNamedNativeQuery(
1137
            'find-all',
1138
            'SELECT * FROM cms_users',
1139
            [
1140
                'resultClass' => CMS\CmsUser::class,
1141
            ]
1142
        );
1143
    }
1144
1145
    /**
1146
     * @group DDC-1663
1147
     *
1148
     * @expectedException \Doctrine\ORM\Mapping\MappingException
1149
     * @expectedExceptionMessage Result set mapping named "find-all" in "Doctrine\Tests\Models\CMS\CmsUser" was already declared, but it must be declared only once
1150
     */
1151
    public function testNamingCollisionSqlResultSetMappingShouldThrowException()
1152
    {
1153
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1154
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1155
1156
        $cm->addSqlResultSetMapping(
1157
            [
1158
            'name'      => 'find-all',
1159
            'entities'  => [
1160
                [
1161
                    'entityClass'   => CMS\CmsUser::class,
1162
                ],
1163
            ],
1164
            ]
1165
        );
1166
1167
        $cm->addSqlResultSetMapping(
1168
            [
1169
            'name'      => 'find-all',
1170
            'entities'  => [
1171
                [
1172
                    'entityClass'   => CMS\CmsUser::class,
1173
                ],
1174
            ],
1175
            ]
1176
        );
1177
    }
1178
1179
    /**
1180
     * @group DDC-1068
1181
     */
1182
    public function testClassCaseSensitivity()
1183
    {
1184
        $cm = new ClassMetadata(strtoupper(CMS\CmsUser::class), $this->metadataBuildingContext);
1185
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1186
1187
        self::assertEquals(CMS\CmsUser::class, $cm->getClassName());
1188
    }
1189
1190
    /**
1191
     * @group DDC-659
1192
     */
1193 View Code Duplication
    public function testLifecycleCallbackNotFound()
1194
    {
1195
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1196
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1197
1198
        $cm->addLifecycleCallback('notfound', 'postLoad');
1199
1200
        $this->expectException(MappingException::class);
1201
        $this->expectExceptionMessage("Entity '" . CMS\CmsUser::class . "' has no method 'notfound' to be registered as lifecycle callback.");
1202
1203
        $cm->validateLifecycleCallbacks(new RuntimeReflectionService());
1204
    }
1205
1206
    /**
1207
     * @group ImproveErrorMessages
1208
     */
1209 View Code Duplication
    public function testTargetEntityNotFound()
1210
    {
1211
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1212
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1213
1214
        $association = new Mapping\ManyToOneAssociationMetadata('address');
1215
1216
        $association->setTargetEntity('UnknownClass');
1217
1218
        $cm->addProperty($association);
1219
1220
        $this->expectException(MappingException::class);
1221
        $this->expectExceptionMessage("The target-entity 'UnknownClass' cannot be found in '" . CMS\CmsUser::class . "#address'.");
1222
1223
        $cm->validateAssociations();
1224
    }
1225
1226
    /**
1227
     * @group DDC-1663
1228
     *
1229
     * @expectedException \Doctrine\ORM\Mapping\MappingException
1230
     * @expectedExceptionMessage Result set mapping named "find-all" in "Doctrine\Tests\Models\CMS\CmsUser requires a entity class name.
1231
     */
1232
    public function testNameIsMandatoryForEntityNameSqlResultSetMappingException()
1233
    {
1234
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1235
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1236
1237
        $cm->addSqlResultSetMapping(
1238
            [
1239
            'name'      => 'find-all',
1240
            'entities'  => [
1241
                [
1242
                    'fields' => []
1243
                ]
1244
            ],
1245
            ]
1246
        );
1247
    }
1248
1249
    /**
1250
     * @group DDC-984
1251
     * @group DDC-559
1252
     * @group DDC-1575
1253
     */
1254
    public function testFullyQualifiedClassNameShouldBeGivenToNamingStrategy()
1255
    {
1256
        $namingStrategy = new MyNamespacedNamingStrategy();
1257
1258
        $this->metadataBuildingContext = new Mapping\ClassMetadataBuildingContext(
1259
            $this->createMock(Mapping\ClassMetadataFactory::class),
1260
            new RuntimeReflectionService(),
1261
            $namingStrategy
1262
        );
1263
1264
        $addressMetadata = new ClassMetadata(CMS\CmsAddress::class, $this->metadataBuildingContext);
1265
        $addressMetadata->setTable(new Mapping\TableMetadata($namingStrategy->classToTableName(CMS\CmsAddress::class)));
1266
1267
        $articleMetadata = new ClassMetadata(DoctrineGlobal_Article::class, $this->metadataBuildingContext);
1268
        $articleMetadata->setTable(new Mapping\TableMetadata($namingStrategy->classToTableName(DoctrineGlobal_Article::class)));
1269
1270
        $routingMetadata = new ClassMetadata(RoutingLeg::class, $this->metadataBuildingContext);
1271
        $routingMetadata->setTable(new Mapping\TableMetadata($namingStrategy->classToTableName(RoutingLeg::class)));
1272
1273
        $association = new Mapping\ManyToManyAssociationMetadata('user');
1274
1275
        $association->setTargetEntity(CMS\CmsUser::class);
1276
1277
        $addressMetadata->addProperty($association);
1278
1279
        $association = new Mapping\ManyToManyAssociationMetadata('author');
1280
1281
        $association->setTargetEntity(CMS\CmsUser::class);
1282
1283
        $articleMetadata->addProperty($association);
1284
1285
        self::assertEquals('routing_routingleg', $routingMetadata->table->getName());
1286
        self::assertEquals('cms_cmsaddress_cms_cmsuser', $addressMetadata->getProperty('user')->getJoinTable()->getName());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\ORM\Mapping\Property as the method getJoinTable() does only exist in the following implementations of said interface: Doctrine\ORM\Mapping\ManyToManyAssociationMetadata.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
1287
        self::assertEquals('doctrineglobal_article_cms_cmsuser', $articleMetadata->getProperty('author')->getJoinTable()->getName());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\ORM\Mapping\Property as the method getJoinTable() does only exist in the following implementations of said interface: Doctrine\ORM\Mapping\ManyToManyAssociationMetadata.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
1288
    }
1289
1290
    /**
1291
     * @group DDC-984
1292
     * @group DDC-559
1293
     */
1294
    public function testFullyQualifiedClassNameShouldBeGivenToNamingStrategyPropertyToColumnName()
1295
    {
1296
        $namingStrategy = new MyPrefixNamingStrategy();
1297
1298
        $this->metadataBuildingContext = new Mapping\ClassMetadataBuildingContext(
1299
            $this->createMock(Mapping\ClassMetadataFactory::class),
1300
            new RuntimeReflectionService(),
1301
            $namingStrategy
1302
        );
1303
1304
        $metadata = new ClassMetadata(CMS\CmsAddress::class, $this->metadataBuildingContext);
1305
        $metadata->setTable(new Mapping\TableMetadata($namingStrategy->classToTableName(CMS\CmsAddress::class)));
1306
1307
        $fieldMetadata = new Mapping\FieldMetadata('country');
1308
1309
        $fieldMetadata->setType(Type::getType('string'));
1310
1311
        $metadata->addProperty($fieldMetadata);
1312
1313
        $fieldMetadata = new Mapping\FieldMetadata('city');
1314
1315
        $fieldMetadata->setType(Type::getType('string'));
1316
1317
        $metadata->addProperty($fieldMetadata);
1318
1319
        self::assertEquals(
1320
            $metadata->fieldNames,
1321
            [
1322
                'cmsaddress_country' => 'country',
1323
                'cmsaddress_city'    => 'city'
1324
            ]
1325
        );
1326
    }
1327
1328
    /**
1329
     * @group DDC-1746
1330
     * @expectedException        \Doctrine\ORM\Mapping\MappingException
1331
     * @expectedExceptionMessage You have specified invalid cascade options for Doctrine\Tests\Models\CMS\CmsUser::$address: 'invalid'; available options: 'remove', 'persist', and 'refresh'
1332
     */
1333 View Code Duplication
    public function testInvalidCascade()
1334
    {
1335
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1336
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1337
1338
        $association = new Mapping\ManyToOneAssociationMetadata('address');
1339
1340
        $association->setTargetEntity('UnknownClass');
1341
        $association->setCascade(['invalid']);
1342
1343
        $cm->addProperty($association);
1344
     }
1345
1346
    /**
1347
     * @group DDC-964
1348
     * @expectedException        \Doctrine\ORM\Mapping\MappingException
1349
     * @expectedExceptionMessage Invalid field override named 'invalidPropertyName' for class 'Doctrine\Tests\Models\DDC964\DDC964Admin'
1350
     */
1351 View Code Duplication
    public function testInvalidPropertyAssociationOverrideNameException()
1352
    {
1353
        $cm = new ClassMetadata(DDC964Admin::class, $this->metadataBuildingContext);
1354
        $cm->setTable(new Mapping\TableMetadata("ddc964_admin"));
1355
1356
        $association = new Mapping\ManyToOneAssociationMetadata('address');
1357
1358
        $association->setTargetEntity(DDC964Address::class);
1359
1360
        $cm->addProperty($association);
1361
1362
        $cm->setPropertyOverride(new Mapping\ManyToOneAssociationMetadata('invalidPropertyName'));
1363
    }
1364
1365
    /**
1366
     * @group DDC-964
1367
     * @expectedException        \Doctrine\ORM\Mapping\MappingException
1368
     * @expectedExceptionMessage Invalid field override named 'invalidPropertyName' for class 'Doctrine\Tests\Models\DDC964\DDC964Guest'.
1369
     */
1370
    public function testInvalidPropertyAttributeOverrideNameException()
1371
    {
1372
        $cm = new ClassMetadata(DDC964Guest::class, $this->metadataBuildingContext);
1373
        $cm->setTable(new Mapping\TableMetadata("ddc964_guest"));
1374
1375
        $fieldMetadata = new Mapping\FieldMetadata('name');
1376
        $fieldMetadata->setType(Type::getType('string'));
1377
1378
        $cm->addProperty($fieldMetadata);
1379
1380
        $fieldMetadata = new Mapping\FieldMetadata('invalidPropertyName');
1381
        $fieldMetadata->setType(Type::getType('string'));
1382
1383
        $cm->setPropertyOverride($fieldMetadata);
1384
    }
1385
1386
    /**
1387
     * @group DDC-1955
1388
     *
1389
     * @expectedException        \Doctrine\ORM\Mapping\MappingException
1390
     * @expectedExceptionMessage Entity Listener "\InvalidClassName" declared on "Doctrine\Tests\Models\CMS\CmsUser" not found.
1391
     */
1392 View Code Duplication
    public function testInvalidEntityListenerClassException()
1393
    {
1394
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1395
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1396
1397
        $cm->addEntityListener(Events::postLoad, '\InvalidClassName', 'postLoadHandler');
1398
    }
1399
1400
    /**
1401
     * @group DDC-1955
1402
     *
1403
     * @expectedException        \Doctrine\ORM\Mapping\MappingException
1404
     * @expectedExceptionMessage Entity Listener "Doctrine\Tests\Models\Company\CompanyContractListener" declared on "Doctrine\Tests\Models\CMS\CmsUser" has no method "invalidMethod".
1405
     */
1406 View Code Duplication
    public function testInvalidEntityListenerMethodException()
1407
    {
1408
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1409
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1410
1411
        $cm->addEntityListener(Events::postLoad, 'Doctrine\Tests\Models\Company\CompanyContractListener', 'invalidMethod');
1412
    }
1413
1414 View Code Duplication
    public function testManyToManySelfReferencingNamingStrategyDefaults()
1415
    {
1416
        $cm = new ClassMetadata(CustomTypeParent::class, $this->metadataBuildingContext);
1417
        $cm->setTable(new Mapping\TableMetadata("custom_type_parent"));
1418
1419
        $association = new Mapping\ManyToManyAssociationMetadata('friendsWithMe');
1420
1421
        $association->setTargetEntity(CustomTypeParent::class);
1422
1423
        $cm->addProperty($association);
1424
1425
        $association = $cm->getProperty('friendsWithMe');
1426
1427
        $joinColumns = [];
1428
1429
        $joinColumn = new Mapping\JoinColumnMetadata();
1430
1431
        $joinColumn->setColumnName("customtypeparent_source");
1432
        $joinColumn->setReferencedColumnName("id");
1433
        $joinColumn->setOnDelete("CASCADE");
1434
1435
        $joinColumns[] = $joinColumn;
1436
1437
        $inverseJoinColumns = [];
1438
1439
        $joinColumn = new Mapping\JoinColumnMetadata();
1440
1441
        $joinColumn->setColumnName("customtypeparent_target");
1442
        $joinColumn->setReferencedColumnName("id");
1443
        $joinColumn->setOnDelete("CASCADE");
1444
1445
        $inverseJoinColumns[] = $joinColumn;
1446
1447
        $joinTable = $association->getJoinTable();
1448
1449
        self::assertEquals('customtypeparent_customtypeparent', $joinTable->getName());
1450
        self::assertEquals($joinColumns, $joinTable->getJoinColumns());
1451
        self::assertEquals($inverseJoinColumns, $joinTable->getInverseJoinColumns());
1452
    }
1453
1454
    /**
1455
     * @group DDC-2662
1456
     */
1457
    public function testQuotedSequenceName()
1458
    {
1459
        $cm = new ClassMetadata(CMS\CmsUser::class, $this->metadataBuildingContext);
1460
        $cm->setTable(new Mapping\TableMetadata('cms_users'));
1461
1462
        $id = new Mapping\FieldMetadata('id');
1463
        $id->setValueGenerator(new Mapping\ValueGeneratorMetadata(
1464
            Mapping\GeneratorType::SEQUENCE,
1465
            [
1466
                'sequenceName' => 'foo',
1467
                'allocationSize' => 1,
1468
            ]
1469
        ));
1470
        $cm->addProperty($id);
1471
1472
        self::assertEquals(
1473
            ['sequenceName' => 'foo', 'allocationSize' => 1],
1474
            $cm->getProperty('id')->getValueGenerator()->getDefinition()
0 ignored issues
show
Bug introduced by
The method getValueGenerator() does not exist on Doctrine\ORM\Mapping\Property. Did you maybe mean getValue()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1475
        );
1476
    }
1477
1478
    /**
1479
     * @group DDC-2700
1480
     */
1481
    public function testIsIdentifierMappedSuperClass()
1482
    {
1483
        $class = new ClassMetadata(DDC2700MappedSuperClass::class, $this->metadataBuildingContext);
1484
1485
        self::assertFalse($class->isIdentifier('foo'));
1486
    }
1487
1488
    /**
1489
     * @group embedded
1490
     */
1491
    public function testWakeupReflectionWithEmbeddableAndStaticReflectionService()
1492
    {
1493
        $metadata = new ClassMetadata(TestEntity1::class, $this->metadataBuildingContext);
1494
        $cm->setTable(new Mapping\TableMetadata("test_entity1"));
0 ignored issues
show
Bug introduced by
The variable $cm does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1495
1496
        $metadata->mapEmbedded(
1497
            [
1498
                'fieldName'    => 'test',
1499
                'class'        => TestEntity1::class,
1500
                'columnPrefix' => false,
1501
            ]
1502
        );
1503
1504
        $fieldMetadata = new Mapping\FieldMetadata('test.embeddedProperty');
1505
        $fieldMetadata->setType(Type::getType('string'));
1506
1507
        $metadata->addProperty($fieldMetadata);
1508
1509
        /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1510
        $mapping = [
1511
            'originalClass' => TestEntity1::class,
1512
            'declaredField' => 'test',
1513
            'originalField' => 'embeddedProperty'
1514
        ];
1515
1516
        $metadata->addProperty('test.embeddedProperty', Type::getType('string'), $mapping);
1517
        */
1518
1519
        $metadata->wakeupReflection(new StaticReflectionService());
1520
1521
        self::assertEquals(
1522
            [
1523
                'test'                  => null,
1524
                'test.embeddedProperty' => null
1525
            ],
1526
            $metadata->getReflectionProperties()
0 ignored issues
show
Bug introduced by
The method getReflectionProperties() does not seem to exist on object<Doctrine\ORM\Mapping\ClassMetadata>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1527
        );
1528
    }
1529
}
1530
1531
/**
1532
 * @ORM\MappedSuperclass
1533
 */
1534
class DDC2700MappedSuperClass
1535
{
1536
    /** @ORM\Column */
1537
    private $foo;
1538
}
1539
1540
class MyNamespacedNamingStrategy extends DefaultNamingStrategy
1541
{
1542
    /**
1543
     * {@inheritdoc}
1544
     */
1545
    public function classToTableName($className)
1546
    {
1547
        if (strpos($className, '\\') !== false) {
1548
            $className = str_replace('\\', '_', str_replace('Doctrine\Tests\Models\\', '', $className));
1549
        }
1550
1551
        return strtolower($className);
1552
    }
1553
}
1554
1555
class MyPrefixNamingStrategy extends DefaultNamingStrategy
1556
{
1557
    /**
1558
     * {@inheritdoc}
1559
     */
1560
    public function propertyToColumnName($propertyName, $className = null)
1561
    {
1562
        return strtolower($this->classToTableName($className)) . '_' . $propertyName;
1563
    }
1564
}
1565