Completed
Push — master ( 6e095f...be1825 )
by Luís
18s
created

EntityGeneratorTest::columnOptionsProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 62
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 46
nc 1
nop 0
dl 0
loc 62
rs 9.4743
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Doctrine\Tests\ORM\Tools;
4
5
use Doctrine\Common\Annotations\AnnotationReader;
6
use Doctrine\Common\Collections\ArrayCollection;
7
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
8
use Doctrine\ORM\Mapping\ClassMetadataFactory;
9
use Doctrine\ORM\Mapping\ClassMetadataInfo;
10
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
11
use Doctrine\ORM\Tools\EntityGenerator;
12
use Doctrine\Tests\Models\DDC2372\DDC2372Admin;
13
use Doctrine\Tests\Models\DDC2372\DDC2372User;
14
use Doctrine\Tests\OrmTestCase;
15
16
class EntityGeneratorTest extends OrmTestCase
17
{
18
19
    /**
20
     * @var EntityGenerator
21
     */
22
    private $_generator;
23
    private $_tmpDir;
24
    private $_namespace;
25
26 View Code Duplication
    public function setUp()
27
    {
28
        $this->_namespace = uniqid("doctrine_");
29
        $this->_tmpDir = \sys_get_temp_dir();
30
        \mkdir($this->_tmpDir . \DIRECTORY_SEPARATOR . $this->_namespace);
31
        $this->_generator = new EntityGenerator();
32
        $this->_generator->setAnnotationPrefix("");
33
        $this->_generator->setGenerateAnnotations(true);
34
        $this->_generator->setGenerateStubMethods(true);
35
        $this->_generator->setRegenerateEntityIfExists(false);
36
        $this->_generator->setUpdateEntityIfExists(true);
37
        $this->_generator->setFieldVisibility(EntityGenerator::FIELD_VISIBLE_PROTECTED);
0 ignored issues
show
Bug introduced by
Doctrine\ORM\Tools\Entit...FIELD_VISIBLE_PROTECTED of type string is incompatible with the type boolean expected by parameter $visibility of Doctrine\ORM\Tools\Entit...r::setFieldVisibility(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

37
        $this->_generator->setFieldVisibility(/** @scrutinizer ignore-type */ EntityGenerator::FIELD_VISIBLE_PROTECTED);
Loading history...
38
    }
39
40
    public function tearDown()
41
    {
42
        $ri = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->_tmpDir . '/' . $this->_namespace));
43
        foreach ($ri AS $file) {
44
            /* @var $file \SplFileInfo */
45
            if ($file->isFile()) {
46
                \unlink($file->getPathname());
47
            }
48
        }
49
        rmdir($this->_tmpDir . '/' . $this->_namespace);
50
    }
51
52
    /**
53
     * @param ClassMetadataInfo[] $embeddedClasses
54
     *
55
     * @return ClassMetadataInfo
56
     */
57
    public function generateBookEntityFixture(array $embeddedClasses = [])
58
    {
59
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorBook');
60
        $metadata->namespace = $this->_namespace;
61
        $metadata->customRepositoryClassName = $this->_namespace  . '\EntityGeneratorBookRepository';
62
63
        $metadata->table['name'] = 'book';
64
        $metadata->table['uniqueConstraints']['name_uniq'] = ['columns' => ['name']];
65
        $metadata->table['indexes']['status_idx'] = ['columns' => ['status']];
66
        $metadata->mapField(['fieldName' => 'name', 'type' => 'string']);
67
        $metadata->mapField(['fieldName' => 'status', 'type' => 'string', 'options' => ['default' => 'published']]);
68
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
69
        $metadata->mapOneToOne(
70
            ['fieldName' => 'author', 'targetEntity' => EntityGeneratorAuthor::class, 'mappedBy' => 'book']
71
        );
72
        $joinColumns = [
0 ignored issues
show
Unused Code introduced by
The assignment to $joinColumns is dead and can be removed.
Loading history...
73
            ['name' => 'author_id', 'referencedColumnName' => 'id']
74
        ];
75
        $metadata->mapManyToMany(
76
            [
77
            'fieldName' => 'comments',
78
            'targetEntity' => EntityGeneratorComment::class,
79
            'fetch' => ClassMetadataInfo::FETCH_EXTRA_LAZY,
80
            'joinTable' => [
81
                'name' => 'book_comment',
82
                'joinColumns' => [['name' => 'book_id', 'referencedColumnName' => 'id']],
83
                'inverseJoinColumns' => [['name' => 'comment_id', 'referencedColumnName' => 'id']],
84
            ],
85
            ]
86
        );
87
        $metadata->addLifecycleCallback('loading', 'postLoad');
88
        $metadata->addLifecycleCallback('willBeRemoved', 'preRemove');
89
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
90
91
        foreach ($embeddedClasses as $fieldName => $embeddedClass) {
92
            $this->mapNestedEmbedded($fieldName, $metadata, $embeddedClass);
93
            $this->mapEmbedded($fieldName, $metadata, $embeddedClass);
94
        }
95
96
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
97
98
        return $metadata;
99
    }
100
101
    private function generateEntityTypeFixture(array $field)
102
    {
103
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityType');
104
        $metadata->namespace = $this->_namespace;
105
106
        $metadata->table['name'] = 'entity_type';
107
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
108
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
109
110
        $name  = $field['fieldName'];
111
        $type  = $field['dbType'];
112
        $metadata->mapField(['fieldName' => $name, 'type' => $type]);
113
114
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
115
116
        return $metadata;
117
    }
118
119
    /**
120
     * @return ClassMetadataInfo
121
     */
122
    private function generateIsbnEmbeddableFixture(array $embeddedClasses = [], $columnPrefix = null)
123
    {
124
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorIsbn');
125
        $metadata->namespace = $this->_namespace;
126
        $metadata->isEmbeddedClass = true;
127
        $metadata->mapField(['fieldName' => 'prefix', 'type' => 'integer']);
128
        $metadata->mapField(['fieldName' => 'groupNumber', 'type' => 'integer']);
129
        $metadata->mapField(['fieldName' => 'publisherNumber', 'type' => 'integer']);
130
        $metadata->mapField(['fieldName' => 'titleNumber', 'type' => 'integer']);
131
        $metadata->mapField(['fieldName' => 'checkDigit', 'type' => 'integer']);
132
133
        foreach ($embeddedClasses as $fieldName => $embeddedClass) {
134
            $this->mapEmbedded($fieldName, $metadata, $embeddedClass, $columnPrefix);
135
        }
136
137
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
138
139
        return $metadata;
140
    }
141
142
    /**
143
     * @return ClassMetadataInfo
144
     */
145
    private function generateTestEmbeddableFixture()
146
    {
147
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorTestEmbeddable');
148
        $metadata->namespace = $this->_namespace;
149
        $metadata->isEmbeddedClass = true;
150
        $metadata->mapField(['fieldName' => 'field1', 'type' => 'integer']);
151
        $metadata->mapField(['fieldName' => 'field2', 'type' => 'integer', 'nullable' => true]);
152
        $metadata->mapField(['fieldName' => 'field3', 'type' => 'datetime']);
153
        $metadata->mapField(['fieldName' => 'field4', 'type' => 'datetime', 'nullable' => true]);
154
155
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
156
157
        return $metadata;
158
    }
159
160
    /**
161
     * @param string            $fieldName
162
     * @param ClassMetadataInfo $classMetadata
163
     * @param ClassMetadataInfo $embeddableMetadata
164
     * @param string|null       $columnPrefix
165
     */
166
    private function mapEmbedded(
167
        $fieldName,
168
        ClassMetadataInfo $classMetadata,
169
        ClassMetadataInfo $embeddableMetadata,
170
        $columnPrefix = false
171
    ) {
172
        $classMetadata->mapEmbedded(
173
            ['fieldName' => $fieldName, 'class' => $embeddableMetadata->name, 'columnPrefix' => $columnPrefix]
174
        );
175
    }
176
177
    /**
178
     * @param string            $fieldName
179
     * @param ClassMetadataInfo $classMetadata
180
     * @param ClassMetadataInfo $embeddableMetadata
181
     */
182
    private function mapNestedEmbedded(
183
        $fieldName,
184
        ClassMetadataInfo $classMetadata,
185
        ClassMetadataInfo $embeddableMetadata
186
    ) {
187
        foreach ($embeddableMetadata->embeddedClasses as $property => $embeddableClass) {
188
            $classMetadata->mapEmbedded(
189
                [
190
                'fieldName' => $fieldName . '.' . $property,
191
                'class' => $embeddableClass['class'],
192
                'columnPrefix' => $embeddableClass['columnPrefix'],
193
                'declaredField' => $embeddableClass['declaredField']
194
                        ? $fieldName . '.' . $embeddableClass['declaredField']
195
                        : $fieldName,
196
                'originalField' => $embeddableClass['originalField'] ?: $property,
197
                ]
198
            );
199
        }
200
    }
201
202
    /**
203
     * @param ClassMetadataInfo $metadata
204
     */
205
    private function loadEntityClass(ClassMetadataInfo $metadata)
206
    {
207
        $className = basename(str_replace('\\', '/', $metadata->name));
208
        $path = $this->_tmpDir . '/' . $this->_namespace . '/' . $className . '.php';
209
210
        $this->assertFileExists($path);
211
212
        require_once $path;
213
    }
214
215
    /**
216
     * @param  ClassMetadataInfo $metadata
217
     *
218
     * @return mixed An instance of the given metadata's class.
219
     */
220
    public function newInstance($metadata)
221
    {
222
        $this->loadEntityClass($metadata);
223
224
        return new $metadata->name;
225
    }
226
227
    /**
228
     * @group GH-6314
229
     */
230
    public function testEmbeddedEntityWithNamedColumnPrefix()
231
    {
232
        $columnPrefix = 'GH6314Prefix_';
233
        $testMetadata = $this->generateTestEmbeddableFixture();
234
        $isbnMetadata = $this->generateIsbnEmbeddableFixture(['testEmbedded' => $testMetadata], $columnPrefix);
235
        $isbnEntity = $this->newInstance($isbnMetadata);
236
        $refClass = new \ReflectionClass($isbnEntity);
237
        self::assertTrue($refClass->hasProperty('testEmbedded'));
238
239
        $docComment = $refClass->getProperty('testEmbedded')->getDocComment();
240
        $needle = sprintf('@Embedded(class="%s", columnPrefix="%s")', $testMetadata->name, $columnPrefix);
241
        self::assertContains($needle, $docComment);
242
    }
243
244
    /**
245
     * @group GH-6314
246
     */
247
    public function testEmbeddedEntityWithoutColumnPrefix()
248
    {
249
        $testMetadata = $this->generateTestEmbeddableFixture();
250
        $isbnMetadata = $this->generateIsbnEmbeddableFixture(['testEmbedded' => $testMetadata], false);
251
        $isbnEntity = $this->newInstance($isbnMetadata);
252
        $refClass = new \ReflectionClass($isbnEntity);
253
        self::assertTrue($refClass->hasProperty('testEmbedded'));
254
255
        $docComment = $refClass->getProperty('testEmbedded')->getDocComment();
256
        $needle = sprintf('@Embedded(class="%s", columnPrefix=false)', $testMetadata->name);
257
        self::assertContains($needle, $docComment);
258
    }
259
260
    public function testGeneratedEntityClass()
261
    {
262
        $testMetadata = $this->generateTestEmbeddableFixture();
263
        $isbnMetadata = $this->generateIsbnEmbeddableFixture(['test' => $testMetadata]);
264
        $metadata = $this->generateBookEntityFixture(['isbn' => $isbnMetadata]);
265
266
        $book = $this->newInstance($metadata);
267
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
268
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', '__construct'), "EntityGeneratorBook::__construct() missing.");
269
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getId'), "EntityGeneratorBook::getId() missing.");
270
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setName'), "EntityGeneratorBook::setName() missing.");
271
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getName'), "EntityGeneratorBook::getName() missing.");
272
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setStatus'), "EntityGeneratorBook::setStatus() missing.");
273
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getStatus'), "EntityGeneratorBook::getStatus() missing.");
274
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setAuthor'), "EntityGeneratorBook::setAuthor() missing.");
275
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getAuthor'), "EntityGeneratorBook::getAuthor() missing.");
276
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getComments'), "EntityGeneratorBook::getComments() missing.");
277
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'addComment'), "EntityGeneratorBook::addComment() missing.");
278
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'removeComment'), "EntityGeneratorBook::removeComment() missing.");
279
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setIsbn'), "EntityGeneratorBook::setIsbn() missing.");
280
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getIsbn'), "EntityGeneratorBook::getIsbn() missing.");
281
282
        $reflClass = new \ReflectionClass($metadata->name);
283
284
        $this->assertCount(6, $reflClass->getProperties());
285
        $this->assertCount(15, $reflClass->getMethods());
286
287
        $this->assertEquals('published', $book->getStatus());
288
289
        $book->setName('Jonathan H. Wage');
290
        $this->assertEquals('Jonathan H. Wage', $book->getName());
291
292
        $reflMethod = new \ReflectionMethod($metadata->name, 'addComment');
293
        $addCommentParameters = $reflMethod->getParameters();
294
        $this->assertEquals('comment', $addCommentParameters[0]->getName());
295
296
        $reflMethod = new \ReflectionMethod($metadata->name, 'removeComment');
297
        $removeCommentParameters = $reflMethod->getParameters();
298
        $this->assertEquals('comment', $removeCommentParameters[0]->getName());
299
300
        $author = new EntityGeneratorAuthor();
301
        $book->setAuthor($author);
302
        $this->assertEquals($author, $book->getAuthor());
303
304
        $comment = new EntityGeneratorComment();
305
        $this->assertInstanceOf($metadata->name, $book->addComment($comment));
306
        $this->assertInstanceOf(ArrayCollection::class, $book->getComments());
307
        $this->assertEquals(new ArrayCollection([$comment]), $book->getComments());
308
        $this->assertInternalType('boolean', $book->removeComment($comment));
309
        $this->assertEquals(new ArrayCollection([]), $book->getComments());
310
311
        $this->newInstance($isbnMetadata);
312
        $isbn = new $isbnMetadata->name();
313
314
        $book->setIsbn($isbn);
315
        $this->assertSame($isbn, $book->getIsbn());
316
317
        $reflMethod = new \ReflectionMethod($metadata->name, 'setIsbn');
318
        $reflParameters = $reflMethod->getParameters();
319
        $this->assertEquals($isbnMetadata->name, $reflParameters[0]->getClass()->name);
320
    }
321
322
    public function testEntityUpdatingWorks()
323
    {
324
        $metadata = $this->generateBookEntityFixture(['isbn' => $this->generateIsbnEmbeddableFixture()]);
325
326
        $metadata->mapField(['fieldName' => 'test', 'type' => 'string']);
327
328
        $testEmbeddableMetadata = $this->generateTestEmbeddableFixture();
329
        $this->mapEmbedded('testEmbedded', $metadata, $testEmbeddableMetadata);
330
331
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
332
333
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
334
335
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $book is dead and can be removed.
Loading history...
336
        $reflClass = new \ReflectionClass($metadata->name);
337
338
        $this->assertTrue($reflClass->hasProperty('name'), "Regenerating keeps property 'name'.");
339
        $this->assertTrue($reflClass->hasProperty('status'), "Regenerating keeps property 'status'.");
340
        $this->assertTrue($reflClass->hasProperty('id'), "Regenerating keeps property 'id'.");
341
        $this->assertTrue($reflClass->hasProperty('isbn'), "Regenerating keeps property 'isbn'.");
342
343
        $this->assertTrue($reflClass->hasProperty('test'), "Check for property test failed.");
344
        $this->assertTrue($reflClass->getProperty('test')->isProtected(), "Check for protected property test failed.");
345
        $this->assertTrue($reflClass->hasProperty('testEmbedded'), "Check for property testEmbedded failed.");
346
        $this->assertTrue($reflClass->getProperty('testEmbedded')->isProtected(), "Check for protected property testEmbedded failed.");
347
        $this->assertTrue($reflClass->hasMethod('getTest'), "Check for method 'getTest' failed.");
348
        $this->assertTrue($reflClass->getMethod('getTest')->isPublic(), "Check for public visibility of method 'getTest' failed.");
349
        $this->assertTrue($reflClass->hasMethod('setTest'), "Check for method 'setTest' failed.");
350
        $this->assertTrue($reflClass->getMethod('setTest')->isPublic(), "Check for public visibility of method 'setTest' failed.");
351
        $this->assertTrue($reflClass->hasMethod('getTestEmbedded'), "Check for method 'getTestEmbedded' failed.");
352
        $this->assertTrue(
353
            $reflClass->getMethod('getTestEmbedded')->isPublic(),
354
            "Check for public visibility of method 'getTestEmbedded' failed."
355
        );
356
        $this->assertTrue($reflClass->hasMethod('setTestEmbedded'), "Check for method 'setTestEmbedded' failed.");
357
        $this->assertTrue(
358
            $reflClass->getMethod('setTestEmbedded')->isPublic(),
359
            "Check for public visibility of method 'setTestEmbedded' failed."
360
        );
361
    }
362
363
    /**
364
     * @group DDC-3152
365
     */
366
    public function testDoesNotRegenerateExistingMethodsWithDifferentCase()
367
    {
368
        $metadata = $this->generateBookEntityFixture(['isbn' => $this->generateIsbnEmbeddableFixture()]);
369
370
        // Workaround to change existing fields case (just to simulate the use case)
371
        $metadata->fieldMappings['status']['fieldName'] = 'STATUS';
372
        $metadata->embeddedClasses['ISBN'] = $metadata->embeddedClasses['isbn'];
373
        unset($metadata->embeddedClasses['isbn']);
374
375
        // Should not throw a PHP fatal error
376
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
377
378
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
379
380
        $this->newInstance($metadata);
381
        $reflClass = new \ReflectionClass($metadata->name);
382
383
        $this->assertTrue($reflClass->hasProperty('status'));
384
        $this->assertTrue($reflClass->hasProperty('STATUS'));
385
        $this->assertTrue($reflClass->hasProperty('isbn'));
386
        $this->assertTrue($reflClass->hasProperty('ISBN'));
387
        $this->assertTrue($reflClass->hasMethod('getStatus'));
388
        $this->assertTrue($reflClass->hasMethod('setStatus'));
389
        $this->assertTrue($reflClass->hasMethod('getIsbn'));
390
        $this->assertTrue($reflClass->hasMethod('setIsbn'));
391
    }
392
393
    /**
394
     * @group DDC-2121
395
     */
396
    public function testMethodDocBlockShouldStartWithBackSlash()
397
    {
398
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
399
        $metadata = $this->generateBookEntityFixture(['isbn' => $embeddedMetadata]);
400
        $book     = $this->newInstance($metadata);
401
402
        $this->assertPhpDocVarType('\Doctrine\Common\Collections\Collection', new \ReflectionProperty($book, 'comments'));
403
        $this->assertPhpDocReturnType('\Doctrine\Common\Collections\Collection', new \ReflectionMethod($book, 'getComments'));
404
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorComment', new \ReflectionMethod($book, 'addComment'));
405
        $this->assertPhpDocReturnType('EntityGeneratorBook', new \ReflectionMethod($book, 'addComment'));
406
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorComment', new \ReflectionMethod($book, 'removeComment'));
407
        $this->assertPhpDocReturnType('boolean', new \ReflectionMethod($book, 'removeComment'));
408
409
        $this->assertPhpDocVarType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', new \ReflectionProperty($book, 'author'));
410
        $this->assertPhpDocReturnType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor|null', new \ReflectionMethod($book, 'getAuthor'));
411
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor|null', new \ReflectionMethod($book, 'setAuthor'));
412
413
        $expectedClassName = '\\' . $embeddedMetadata->name;
414
        $this->assertPhpDocVarType($expectedClassName, new \ReflectionProperty($book, 'isbn'));
415
        $this->assertPhpDocReturnType($expectedClassName, new \ReflectionMethod($book, 'getIsbn'));
416
        $this->assertPhpDocParamType($expectedClassName, new \ReflectionMethod($book, 'setIsbn'));
417
    }
418
419
    public function testEntityExtendsStdClass()
420
    {
421
        $this->_generator->setClassToExtend('stdClass');
422
        $metadata = $this->generateBookEntityFixture();
423
424
        $book = $this->newInstance($metadata);
425
        $this->assertInstanceOf('stdClass', $book);
426
427
        $metadata = $this->generateIsbnEmbeddableFixture();
428
        $isbn = $this->newInstance($metadata);
429
        $this->assertInstanceOf('stdClass', $isbn);
430
    }
431
432
    public function testLifecycleCallbacks()
433
    {
434
        $metadata = $this->generateBookEntityFixture();
435
436
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $book is dead and can be removed.
Loading history...
437
        $reflClass = new \ReflectionClass($metadata->name);
438
439
        $this->assertTrue($reflClass->hasMethod('loading'), "Check for postLoad lifecycle callback.");
440
        $this->assertTrue($reflClass->hasMethod('willBeRemoved'), "Check for preRemove lifecycle callback.");
441
    }
442
443
    public function testLoadMetadata()
444
    {
445
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
446
        $metadata = $this->generateBookEntityFixture(['isbn' => $embeddedMetadata]);
447
448
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $book is dead and can be removed.
Loading history...
449
450
        $reflectionService = new RuntimeReflectionService();
451
452
        $cm = new ClassMetadataInfo($metadata->name);
453
        $cm->initializeReflection($reflectionService);
454
455
        $driver = $this->createAnnotationDriver();
456
        $driver->loadMetadataForClass($cm->name, $cm);
457
458
        $this->assertEquals($cm->columnNames, $metadata->columnNames);
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ORM\Mapping\Cla...adataInfo::$columnNames has been deprecated: 3.0 Remove this. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

458
        $this->assertEquals(/** @scrutinizer ignore-deprecated */ $cm->columnNames, $metadata->columnNames);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
459
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
460
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
461
        $this->assertEquals($cm->identifier, $metadata->identifier);
462
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
463
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
464
        $this->assertEquals($cm->embeddedClasses, $metadata->embeddedClasses);
465
        $this->assertEquals($cm->isEmbeddedClass, $metadata->isEmbeddedClass);
466
467
        $this->assertEquals(ClassMetadataInfo::FETCH_EXTRA_LAZY, $cm->associationMappings['comments']['fetch']);
468
469
        $isbn = $this->newInstance($embeddedMetadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $isbn is dead and can be removed.
Loading history...
470
471
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
472
        $cm->initializeReflection($reflectionService);
473
474
        $driver->loadMetadataForClass($cm->name, $cm);
475
476
        $this->assertEquals($cm->columnNames, $embeddedMetadata->columnNames);
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ORM\Mapping\Cla...adataInfo::$columnNames has been deprecated: 3.0 Remove this. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

476
        $this->assertEquals(/** @scrutinizer ignore-deprecated */ $cm->columnNames, $embeddedMetadata->columnNames);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
477
        $this->assertEquals($cm->embeddedClasses, $embeddedMetadata->embeddedClasses);
478
        $this->assertEquals($cm->isEmbeddedClass, $embeddedMetadata->isEmbeddedClass);
479
    }
480
481
    public function testLoadPrefixedMetadata()
482
    {
483
        $this->_generator->setAnnotationPrefix('ORM\\');
484
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
485
        $metadata = $this->generateBookEntityFixture(['isbn' => $embeddedMetadata]);
486
487
        $reader = new AnnotationReader();
488
        $driver = new AnnotationDriver($reader, []);
489
490
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $book is dead and can be removed.
Loading history...
491
492
        $reflectionService = new RuntimeReflectionService();
493
494
        $cm = new ClassMetadataInfo($metadata->name);
495
        $cm->initializeReflection($reflectionService);
496
497
        $driver->loadMetadataForClass($cm->name, $cm);
498
499
        $this->assertEquals($cm->columnNames, $metadata->columnNames);
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ORM\Mapping\Cla...adataInfo::$columnNames has been deprecated: 3.0 Remove this. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

499
        $this->assertEquals($cm->columnNames, /** @scrutinizer ignore-deprecated */ $metadata->columnNames);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
500
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
501
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
502
        $this->assertEquals($cm->identifier, $metadata->identifier);
503
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
504
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
505
506
        $isbn = $this->newInstance($embeddedMetadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $isbn is dead and can be removed.
Loading history...
507
508
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
509
        $cm->initializeReflection($reflectionService);
510
511
        $driver->loadMetadataForClass($cm->name, $cm);
512
513
        $this->assertEquals($cm->columnNames, $embeddedMetadata->columnNames);
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ORM\Mapping\Cla...adataInfo::$columnNames has been deprecated: 3.0 Remove this. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

513
        $this->assertEquals(/** @scrutinizer ignore-deprecated */ $cm->columnNames, $embeddedMetadata->columnNames);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
514
        $this->assertEquals($cm->embeddedClasses, $embeddedMetadata->embeddedClasses);
515
        $this->assertEquals($cm->isEmbeddedClass, $embeddedMetadata->isEmbeddedClass);
516
    }
517
518
    /**
519
     * @group DDC-3272
520
     */
521
    public function testMappedSuperclassAnnotationGeneration()
522
    {
523
        $metadata                     = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorBook');
524
        $metadata->namespace          = $this->_namespace;
525
        $metadata->isMappedSuperclass = true;
526
527
        $this->_generator->setAnnotationPrefix('ORM\\');
528
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
529
        $this->newInstance($metadata); // force instantiation (causes autoloading to kick in)
530
531
        $driver = new AnnotationDriver(new AnnotationReader(), []);
532
        $cm     = new ClassMetadataInfo($metadata->name);
533
534
        $cm->initializeReflection(new RuntimeReflectionService);
535
        $driver->loadMetadataForClass($cm->name, $cm);
536
537
        $this->assertTrue($cm->isMappedSuperclass);
538
    }
539
540
    /**
541
     * @dataProvider getParseTokensInEntityFileData
542
     */
543
    public function testParseTokensInEntityFile($php, $classes)
544
    {
545
        $r = new \ReflectionObject($this->_generator);
546
        $m = $r->getMethod('parseTokensInEntityFile');
547
        $m->setAccessible(true);
548
549
        $p = $r->getProperty('staticReflection');
550
        $p->setAccessible(true);
551
552
        $ret = $m->invoke($this->_generator, $php);
0 ignored issues
show
Unused Code introduced by
The assignment to $ret is dead and can be removed.
Loading history...
553
        $this->assertEquals($classes, array_keys($p->getValue($this->_generator)));
554
    }
555
556
    /**
557
     * @group DDC-1784
558
     */
559
    public function testGenerateEntityWithSequenceGenerator()
560
    {
561
        $metadata               = new ClassMetadataInfo($this->_namespace . '\DDC1784Entity');
562
        $metadata->namespace    = $this->_namespace;
563
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
564
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
565
        $metadata->setSequenceGeneratorDefinition(
566
            [
567
            'sequenceName'      => 'DDC1784_ID_SEQ',
568
            'allocationSize'    => 1,
569
            'initialValue'      => 2
570
            ]
571
        );
572
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
573
574
        $filename = $this->_tmpDir . DIRECTORY_SEPARATOR
575
                  . $this->_namespace . DIRECTORY_SEPARATOR . 'DDC1784Entity.php';
576
577
        $this->assertFileExists($filename);
578
        require_once $filename;
579
580
581
        $reflection = new \ReflectionProperty($metadata->name, 'id');
582
        $docComment = $reflection->getDocComment();
583
584
        $this->assertContains('@Id', $docComment);
585
        $this->assertContains('@Column(name="id", type="integer")', $docComment);
586
        $this->assertContains('@GeneratedValue(strategy="SEQUENCE")', $docComment);
587
        $this->assertContains('@SequenceGenerator(sequenceName="DDC1784_ID_SEQ", allocationSize=1, initialValue=2)', $docComment);
588
    }
589
590
    /**
591
     * @group DDC-2079
592
     */
593
    public function testGenerateEntityWithMultipleInverseJoinColumns()
594
    {
595
        $metadata               = new ClassMetadataInfo($this->_namespace . '\DDC2079Entity');
596
        $metadata->namespace    = $this->_namespace;
597
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
598
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
599
        $metadata->mapManyToMany(
600
            [
601
            'fieldName'     => 'centroCustos',
602
            'targetEntity'  => 'DDC2079CentroCusto',
603
            'joinTable'     => [
604
                'name'                  => 'unidade_centro_custo',
605
                'joinColumns'           => [
606
                    ['name' => 'idorcamento',      'referencedColumnName' => 'idorcamento'],
607
                    ['name' => 'idunidade',        'referencedColumnName' => 'idunidade']
608
                ],
609
                'inverseJoinColumns'    => [
610
                    ['name' => 'idcentrocusto',    'referencedColumnName' => 'idcentrocusto'],
611
                    ['name' => 'idpais',           'referencedColumnName' => 'idpais'],
612
                ],
613
            ],
614
            ]
615
        );
616
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
617
618
        $filename = $this->_tmpDir . DIRECTORY_SEPARATOR
619
            . $this->_namespace . DIRECTORY_SEPARATOR . 'DDC2079Entity.php';
620
621
        $this->assertFileExists($filename);
622
        require_once $filename;
623
624
        $property   = new \ReflectionProperty($metadata->name, 'centroCustos');
625
        $docComment = $property->getDocComment();
626
627
        //joinColumns
628
        $this->assertContains('@JoinColumn(name="idorcamento", referencedColumnName="idorcamento"),', $docComment);
629
        $this->assertContains('@JoinColumn(name="idunidade", referencedColumnName="idunidade")', $docComment);
630
        //inverseJoinColumns
631
        $this->assertContains('@JoinColumn(name="idcentrocusto", referencedColumnName="idcentrocusto"),', $docComment);
632
        $this->assertContains('@JoinColumn(name="idpais", referencedColumnName="idpais")', $docComment);
633
634
    }
635
636
     /**
637
     * @group DDC-2172
638
     */
639 View Code Duplication
    public function testGetInheritanceTypeString()
640
    {
641
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadataInfo');
642
        $method     = new \ReflectionMethod($this->_generator, 'getInheritanceTypeString');
643
        $constants  = $reflection->getConstants();
644
        $pattern    = '/^INHERITANCE_TYPE_/';
645
646
        $method->setAccessible(true);
647
648
        foreach ($constants as $name => $value) {
649
            if( ! preg_match($pattern, $name)) {
650
                continue;
651
            }
652
653
            $expected = preg_replace($pattern, '', $name);
654
            $actual   = $method->invoke($this->_generator, $value);
655
656
            $this->assertEquals($expected, $actual);
657
        }
658
659
        $this->expectException(\InvalidArgumentException::class);
660
        $this->expectExceptionMessage('Invalid provided InheritanceType: INVALID');
661
662
        $method->invoke($this->_generator, 'INVALID');
663
    }
664
665
    /**
666
    * @group DDC-2172
667
    */
668 View Code Duplication
    public function testGetChangeTrackingPolicyString()
669
    {
670
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadata');
671
        $method     = new \ReflectionMethod($this->_generator, 'getChangeTrackingPolicyString');
672
        $constants  = $reflection->getConstants();
673
        $pattern    = '/^CHANGETRACKING_/';
674
675
        $method->setAccessible(true);
676
677
        foreach ($constants as $name => $value) {
678
            if( ! preg_match($pattern, $name)) {
679
                continue;
680
            }
681
682
            $expected = preg_replace($pattern, '', $name);
683
            $actual   = $method->invoke($this->_generator, $value);
684
685
            $this->assertEquals($expected, $actual);
686
        }
687
688
        $this->expectException(\InvalidArgumentException::class);
689
        $this->expectExceptionMessage('Invalid provided ChangeTrackingPolicy: INVALID');
690
691
        $method->invoke($this->_generator, 'INVALID');
692
    }
693
694
    /**
695
     * @group DDC-2172
696
     */
697 View Code Duplication
    public function testGetIdGeneratorTypeString()
698
    {
699
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadataInfo');
700
        $method     = new \ReflectionMethod($this->_generator, 'getIdGeneratorTypeString');
701
        $constants  = $reflection->getConstants();
702
        $pattern    = '/^GENERATOR_TYPE_/';
703
704
        $method->setAccessible(true);
705
706
        foreach ($constants as $name => $value) {
707
            if( ! preg_match($pattern, $name)) {
708
                continue;
709
            }
710
711
            $expected = preg_replace($pattern, '', $name);
712
            $actual   = $method->invoke($this->_generator, $value);
713
714
            $this->assertEquals($expected, $actual);
715
        }
716
717
        $this->expectException(\InvalidArgumentException::class);
718
        $this->expectExceptionMessage('Invalid provided IdGeneratorType: INVALID');
719
720
        $method->invoke($this->_generator, 'INVALID');
721
    }
722
723
    /**
724
     * @dataProvider getEntityTypeAliasDataProvider
725
     *
726
     * @group DDC-1694
727
     */
728
    public function testEntityTypeAlias(array $field)
729
    {
730
        $metadata   = $this->generateEntityTypeFixture($field);
731
        $path       = $this->_tmpDir . '/'. $this->_namespace . '/EntityType.php';
732
733
        $this->assertFileExists($path);
734
        require_once $path;
735
736
        $entity     = new $metadata->name;
737
        $reflClass  = new \ReflectionClass($metadata->name);
738
739
        $type   = $field['phpType'];
740
        $name   = $field['fieldName'];
741
        $value  = $field['value'];
742
        $getter = "get" . ucfirst($name);
743
        $setter = "set" . ucfirst($name);
744
745
        $this->assertPhpDocVarType($type, $reflClass->getProperty($name));
746
        $this->assertPhpDocParamType($type, $reflClass->getMethod($setter));
747
        $this->assertPhpDocReturnType($type, $reflClass->getMethod($getter));
748
749
        $this->assertSame($entity, $entity->{$setter}($value));
750
        $this->assertEquals($value, $entity->{$getter}());
751
    }
752
753
    /**
754
     * @group DDC-2372
755
     */
756 View Code Duplication
    public function testTraitPropertiesAndMethodsAreNotDuplicated()
757
    {
758
        $cmf = new ClassMetadataFactory();
759
        $em = $this->_getTestEntityManager();
760
        $cmf->setEntityManager($em);
761
762
        $user = new DDC2372User();
763
        $metadata = $cmf->getMetadataFor(get_class($user));
764
        $metadata->name = $this->_namespace . "\DDC2372User";
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
765
        $metadata->namespace = $this->_namespace;
0 ignored issues
show
Bug introduced by
Accessing namespace on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
766
767
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
768
769
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/DDC2372User.php");
770
        require $this->_tmpDir . "/" . $this->_namespace . "/DDC2372User.php";
771
772
        $reflClass = new \ReflectionClass($metadata->name);
773
774
        $this->assertSame($reflClass->hasProperty('address'), false);
775
        $this->assertSame($reflClass->hasMethod('setAddress'), false);
776
        $this->assertSame($reflClass->hasMethod('getAddress'), false);
777
    }
778
779
    /**
780
     * @group DDC-2372
781
     */
782 View Code Duplication
    public function testTraitPropertiesAndMethodsAreNotDuplicatedInChildClasses()
783
    {
784
        $cmf = new ClassMetadataFactory();
785
        $em = $this->_getTestEntityManager();
786
        $cmf->setEntityManager($em);
787
788
        $user = new DDC2372Admin();
789
        $metadata = $cmf->getMetadataFor(get_class($user));
790
        $metadata->name = $this->_namespace . "\DDC2372Admin";
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
791
        $metadata->namespace = $this->_namespace;
0 ignored issues
show
Bug introduced by
Accessing namespace on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
792
793
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
794
795
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/DDC2372Admin.php");
796
        require $this->_tmpDir . "/" . $this->_namespace . "/DDC2372Admin.php";
797
798
        $reflClass = new \ReflectionClass($metadata->name);
799
800
        $this->assertSame($reflClass->hasProperty('address'), false);
801
        $this->assertSame($reflClass->hasMethod('setAddress'), false);
802
        $this->assertSame($reflClass->hasMethod('getAddress'), false);
803
    }
804
805
    /**
806
     * @group DDC-1590
807
     */
808
    public function testMethodsAndPropertiesAreNotDuplicatedInChildClasses()
809
    {
810
        $cmf    = new ClassMetadataFactory();
811
        $em     = $this->_getTestEntityManager();
812
813
        $cmf->setEntityManager($em);
814
815
        $ns     = $this->_namespace;
816
        $nsdir  = $this->_tmpDir . '/' . $ns;
817
818
        $content = str_replace(
819
            'namespace Doctrine\Tests\Models\DDC1590',
820
            'namespace ' . $ns,
821
            file_get_contents(__DIR__ . '/../../Models/DDC1590/DDC1590User.php')
822
        );
823
824
        $fname = $nsdir . "/DDC1590User.php";
825
        file_put_contents($fname, $content);
826
        require $fname;
827
828
829
        $metadata = $cmf->getMetadataFor($ns . '\DDC1590User');
830
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
831
832
        // class DDC1590User extends DDC1590Entity { ... }
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% 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...
833
        $source = file_get_contents($fname);
834
835
        // class _DDC1590User extends DDC1590Entity { ... }
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% 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...
836
        $source2    = str_replace('class DDC1590User', 'class _DDC1590User', $source);
837
        $fname2     = $nsdir . "/_DDC1590User.php";
838
        file_put_contents($fname2, $source2);
839
        require $fname2;
840
841
        // class __DDC1590User { ... }
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% 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...
842
        $source3    = str_replace('class DDC1590User extends DDC1590Entity', 'class __DDC1590User', $source);
843
        $fname3     = $nsdir . "/__DDC1590User.php";
844
        file_put_contents($fname3, $source3);
845
        require $fname3;
846
847
848
        // class _DDC1590User extends DDC1590Entity { ... }
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% 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...
849
        $rc2 = new \ReflectionClass($ns.'\_DDC1590User');
850
851
        $this->assertTrue($rc2->hasProperty('name'));
852
        $this->assertTrue($rc2->hasProperty('id'));
853
        $this->assertTrue($rc2->hasProperty('created_at'));
854
855
        $this->assertTrue($rc2->hasMethod('getName'));
856
        $this->assertTrue($rc2->hasMethod('setName'));
857
        $this->assertTrue($rc2->hasMethod('getId'));
858
        $this->assertFalse($rc2->hasMethod('setId'));
859
        $this->assertTrue($rc2->hasMethod('getCreatedAt'));
860
        $this->assertTrue($rc2->hasMethod('setCreatedAt'));
861
862
863
        // class __DDC1590User { ... }
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% 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...
864
        $rc3 = new \ReflectionClass($ns.'\__DDC1590User');
865
866
        $this->assertTrue($rc3->hasProperty('name'));
867
        $this->assertFalse($rc3->hasProperty('id'));
868
        $this->assertFalse($rc3->hasProperty('created_at'));
869
870
        $this->assertTrue($rc3->hasMethod('getName'));
871
        $this->assertTrue($rc3->hasMethod('setName'));
872
        $this->assertFalse($rc3->hasMethod('getId'));
873
        $this->assertFalse($rc3->hasMethod('setId'));
874
        $this->assertFalse($rc3->hasMethod('getCreatedAt'));
875
        $this->assertFalse($rc3->hasMethod('setCreatedAt'));
876
    }
877
878
    /**
879
     * @group DDC-3304
880
     */
881
    public function testGeneratedMutableEmbeddablesClass()
882
    {
883
        $embeddedMetadata = $this->generateTestEmbeddableFixture();
884
        $metadata = $this->generateIsbnEmbeddableFixture(['test' => $embeddedMetadata]);
885
886
        $isbn = $this->newInstance($metadata);
887
888
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
889
        $this->assertFalse(method_exists($metadata->name, '__construct'), "EntityGeneratorIsbn::__construct present.");
890
        $this->assertTrue(method_exists($metadata->name, 'getPrefix'), "EntityGeneratorIsbn::getPrefix() missing.");
891
        $this->assertTrue(method_exists($metadata->name, 'setPrefix'), "EntityGeneratorIsbn::setPrefix() missing.");
892
        $this->assertTrue(method_exists($metadata->name, 'getGroupNumber'), "EntityGeneratorIsbn::getGroupNumber() missing.");
893
        $this->assertTrue(method_exists($metadata->name, 'setGroupNumber'), "EntityGeneratorIsbn::setGroupNumber() missing.");
894
        $this->assertTrue(method_exists($metadata->name, 'getPublisherNumber'), "EntityGeneratorIsbn::getPublisherNumber() missing.");
895
        $this->assertTrue(method_exists($metadata->name, 'setPublisherNumber'), "EntityGeneratorIsbn::setPublisherNumber() missing.");
896
        $this->assertTrue(method_exists($metadata->name, 'getTitleNumber'), "EntityGeneratorIsbn::getTitleNumber() missing.");
897
        $this->assertTrue(method_exists($metadata->name, 'setTitleNumber'), "EntityGeneratorIsbn::setTitleNumber() missing.");
898
        $this->assertTrue(method_exists($metadata->name, 'getCheckDigit'), "EntityGeneratorIsbn::getCheckDigit() missing.");
899
        $this->assertTrue(method_exists($metadata->name, 'setCheckDigit'), "EntityGeneratorIsbn::setCheckDigit() missing.");
900
        $this->assertTrue(method_exists($metadata->name, 'getTest'), "EntityGeneratorIsbn::getTest() missing.");
901
        $this->assertTrue(method_exists($metadata->name, 'setTest'), "EntityGeneratorIsbn::setTest() missing.");
902
903
        $isbn->setPrefix(978);
904
        $this->assertSame(978, $isbn->getPrefix());
905
906
        $this->newInstance($embeddedMetadata);
907
        $test = new $embeddedMetadata->name();
908
909
        $isbn->setTest($test);
910
        $this->assertSame($test, $isbn->getTest());
911
912
        $reflMethod = new \ReflectionMethod($metadata->name, 'setTest');
913
        $reflParameters = $reflMethod->getParameters();
914
        $this->assertEquals($embeddedMetadata->name, $reflParameters[0]->getClass()->name);
915
    }
916
917
    /**
918
     * @group DDC-3304
919
     */
920
    public function testGeneratedImmutableEmbeddablesClass()
921
    {
922
        $this->_generator->setEmbeddablesImmutable(true);
923
        $embeddedMetadata = $this->generateTestEmbeddableFixture();
924
        $metadata = $this->generateIsbnEmbeddableFixture(['test' => $embeddedMetadata]);
925
926
        $this->loadEntityClass($embeddedMetadata);
927
        $this->loadEntityClass($metadata);
928
929
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
930
        $this->assertTrue(method_exists($metadata->name, '__construct'), "EntityGeneratorIsbn::__construct missing.");
931
        $this->assertTrue(method_exists($metadata->name, 'getPrefix'), "EntityGeneratorIsbn::getPrefix() missing.");
932
        $this->assertFalse(method_exists($metadata->name, 'setPrefix'), "EntityGeneratorIsbn::setPrefix() present.");
933
        $this->assertTrue(method_exists($metadata->name, 'getGroupNumber'), "EntityGeneratorIsbn::getGroupNumber() missing.");
934
        $this->assertFalse(method_exists($metadata->name, 'setGroupNumber'), "EntityGeneratorIsbn::setGroupNumber() present.");
935
        $this->assertTrue(method_exists($metadata->name, 'getPublisherNumber'), "EntityGeneratorIsbn::getPublisherNumber() missing.");
936
        $this->assertFalse(method_exists($metadata->name, 'setPublisherNumber'), "EntityGeneratorIsbn::setPublisherNumber() present.");
937
        $this->assertTrue(method_exists($metadata->name, 'getTitleNumber'), "EntityGeneratorIsbn::getTitleNumber() missing.");
938
        $this->assertFalse(method_exists($metadata->name, 'setTitleNumber'), "EntityGeneratorIsbn::setTitleNumber() present.");
939
        $this->assertTrue(method_exists($metadata->name, 'getCheckDigit'), "EntityGeneratorIsbn::getCheckDigit() missing.");
940
        $this->assertFalse(method_exists($metadata->name, 'setCheckDigit'), "EntityGeneratorIsbn::setCheckDigit() present.");
941
        $this->assertTrue(method_exists($metadata->name, 'getTest'), "EntityGeneratorIsbn::getTest() missing.");
942
        $this->assertFalse(method_exists($metadata->name, 'setTest'), "EntityGeneratorIsbn::setTest() present.");
943
944
        $test = new $embeddedMetadata->name(1, new \DateTime());
945
        $isbn = new $metadata->name($test, 978, 3, 12, 732320, 83);
946
947
        $reflMethod = new \ReflectionMethod($isbn, '__construct');
948
        $reflParameters = $reflMethod->getParameters();
949
950
        $this->assertCount(6, $reflParameters);
951
952
        $this->assertSame($embeddedMetadata->name, $reflParameters[0]->getClass()->name);
953
        $this->assertSame('test', $reflParameters[0]->getName());
954
        $this->assertFalse($reflParameters[0]->isOptional());
955
956
        $this->assertSame('prefix', $reflParameters[1]->getName());
957
        $this->assertFalse($reflParameters[1]->isOptional());
958
959
        $this->assertSame('groupNumber', $reflParameters[2]->getName());
960
        $this->assertFalse($reflParameters[2]->isOptional());
961
962
        $this->assertSame('publisherNumber', $reflParameters[3]->getName());
963
        $this->assertFalse($reflParameters[3]->isOptional());
964
965
        $this->assertSame('titleNumber', $reflParameters[4]->getName());
966
        $this->assertFalse($reflParameters[4]->isOptional());
967
968
        $this->assertSame('checkDigit', $reflParameters[5]->getName());
969
        $this->assertFalse($reflParameters[5]->isOptional());
970
971
        $reflMethod = new \ReflectionMethod($test, '__construct');
972
        $reflParameters = $reflMethod->getParameters();
973
974
        $this->assertCount(4, $reflParameters);
975
976
        $this->assertSame('field1', $reflParameters[0]->getName());
977
        $this->assertFalse($reflParameters[0]->isOptional());
978
979
        $this->assertSame('DateTime', $reflParameters[1]->getClass()->name);
980
        $this->assertSame('field3', $reflParameters[1]->getName());
981
        $this->assertFalse($reflParameters[1]->isOptional());
982
983
        $this->assertSame('field2', $reflParameters[2]->getName());
984
        $this->assertTrue($reflParameters[2]->isOptional());
985
986
        $this->assertSame('DateTime', $reflParameters[3]->getClass()->name);
987
        $this->assertSame('field4', $reflParameters[3]->getName());
988
        $this->assertTrue($reflParameters[3]->isOptional());
989
    }
990
991
    public function testRegenerateEntityClass()
992
    {
993
        $metadata = $this->generateBookEntityFixture();
994
        $this->loadEntityClass($metadata);
995
996
        $className = basename(str_replace('\\', '/', $metadata->name));
997
        $path = $this->_tmpDir . '/' . $this->_namespace . '/' . $className . '.php';
998
        $classTest = file_get_contents($path);
999
1000
        $this->_generator->setRegenerateEntityIfExists(true);
1001
        $this->_generator->setBackupExisting(false);
1002
1003
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
1004
        $classNew = file_get_contents($path);
1005
1006
        $this->assertSame($classTest,$classNew);
1007
    }
1008
1009
    /**
1010
     * @return array
1011
     */
1012
    public function getEntityTypeAliasDataProvider()
1013
    {
1014
        return [
1015
            [
1016
                [
1017
                'fieldName' => 'datetimetz',
1018
                'phpType' => '\\DateTime',
1019
                'dbType' => 'datetimetz',
1020
                'value' => new \DateTime
1021
                ]
1022
            ],
1023
            [
1024
                [
1025
                'fieldName' => 'datetime',
1026
                'phpType' => '\\DateTime',
1027
                'dbType' => 'datetime',
1028
                'value' => new \DateTime
1029
                ]
1030
            ],
1031
            [
1032
                [
1033
                'fieldName' => 'date',
1034
                'phpType' => '\\DateTime',
1035
                'dbType' => 'date',
1036
                'value' => new \DateTime
1037
                ]
1038
            ],
1039
            [
1040
                [
1041
                'fieldName' => 'time',
1042
                'phpType' => '\DateTime',
1043
                'dbType' => 'time',
1044
                'value' => new \DateTime
1045
                ]
1046
            ],
1047
            [
1048
                [
1049
                'fieldName' => 'object',
1050
                'phpType' => '\stdClass',
1051
                'dbType' => 'object',
1052
                'value' => new \stdClass()
1053
                ]
1054
            ],
1055
            [
1056
                [
1057
                'fieldName' => 'bigint',
1058
                'phpType' => 'int',
1059
                'dbType' => 'bigint',
1060
                'value' => 11
1061
                ]
1062
            ],
1063
            [
1064
                [
1065
                'fieldName' => 'smallint',
1066
                'phpType' => 'int',
1067
                'dbType' => 'smallint',
1068
                'value' => 22
1069
                ]
1070
            ],
1071
            [
1072
                [
1073
                'fieldName' => 'text',
1074
                'phpType' => 'string',
1075
                'dbType' => 'text',
1076
                'value' => 'text'
1077
                ]
1078
            ],
1079
            [
1080
                [
1081
                'fieldName' => 'blob',
1082
                'phpType' => 'string',
1083
                'dbType' => 'blob',
1084
                'value' => 'blob'
1085
                ]
1086
            ],
1087
            [
1088
                [
1089
                'fieldName' => 'decimal',
1090
                'phpType' => 'string',
1091
                'dbType' => 'decimal',
1092
                'value' => '12.34'
1093
                ],
1094
            ]
1095
        ];
1096
    }
1097
1098
    public function getParseTokensInEntityFileData()
1099
    {
1100
        return [
1101
            [
1102
                '<?php namespace Foo\Bar; class Baz {}',
1103
                ['Foo\Bar\Baz'],
1104
            ],
1105
            [
1106
                '<?php namespace Foo\Bar; use Foo; class Baz {}',
1107
                ['Foo\Bar\Baz'],
1108
            ],
1109
            [
1110
                '<?php namespace /*Comment*/ Foo\Bar; /** Foo */class /* Comment */ Baz {}',
1111
                ['Foo\Bar\Baz'],
1112
            ],
1113
            [
1114
                '
1115
<?php namespace
1116
/*Comment*/
1117
Foo\Bar
1118
;
1119
1120
/** Foo */
1121
class
1122
/* Comment */
1123
 Baz {}
1124
     ',
1125
                ['Foo\Bar\Baz'],
1126
            ],
1127
            [
1128
                '
1129
<?php namespace Foo\Bar; class Baz {
1130
    public static function someMethod(){
1131
        return self::class;
1132
    }
1133
}
1134
',
1135
                ['Foo\Bar\Baz'],
1136
            ],
1137
        ];
1138
    }
1139
1140
    /**
1141
     * @param string $type
1142
     * @param \ReflectionProperty $property
1143
     */
1144 View Code Duplication
    private function assertPhpDocVarType($type, \ReflectionProperty $property)
1145
    {
1146
        $docComment = $property->getDocComment();
1147
        $regex      = '/@var\s+([\S]+)$/m';
1148
1149
        $this->assertRegExp($regex, $docComment);
1150
        $this->assertEquals(1, preg_match($regex, $docComment, $matches));
1151
        $this->assertEquals($type, $matches[1]);
1152
    }
1153
1154
    /**
1155
     * @param string $type
1156
     * @param \ReflectionMethod $method
1157
     */
1158 View Code Duplication
    private function assertPhpDocReturnType($type, \ReflectionMethod $method)
1159
    {
1160
        $docComment = $method->getDocComment();
1161
        $regex      = '/@return\s+([\S]+)(\s+.*)$/m';
1162
1163
        $this->assertRegExp($regex, $docComment);
1164
        $this->assertEquals(1, preg_match($regex, $docComment, $matches));
1165
        $this->assertEquals($type, $matches[1]);
1166
    }
1167
1168
    /**
1169
     * @param string $type
1170
     * @param \ReflectionProperty $method
1171
     */
1172
    private function assertPhpDocParamType($type, \ReflectionMethod $method)
1173
    {
1174
        $this->assertEquals(1, preg_match('/@param\s+([^\s]+)/', $method->getDocComment(), $matches));
1175
        $this->assertEquals($type, $matches[1]);
1176
    }
1177
1178
    /**
1179
     * @group 6703
1180
     *
1181
     * @dataProvider columnOptionsProvider
1182
     */
1183
    public function testOptionsAreGeneratedProperly(string $expectedAnnotation, array $fieldConfiguration) : void
1184
    {
1185
        $metadata               = new ClassMetadataInfo($this->_namespace . '\GH6703Options');
1186
        $metadata->namespace    = $this->_namespace;
1187
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
1188
        $metadata->mapField(['fieldName' => 'test'] + $fieldConfiguration);
1189
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
1190
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
1191
1192
        $filename = $this->_tmpDir . DIRECTORY_SEPARATOR . $this->_namespace . DIRECTORY_SEPARATOR . 'GH6703Options.php';
1193
1194
        self::assertFileExists($filename);
1195
        require_once $filename;
1196
1197
        $property   = new \ReflectionProperty($metadata->name, 'test');
1198
        $docComment = $property->getDocComment();
1199
1200
        self::assertContains($expectedAnnotation, $docComment);
1201
    }
1202
1203
    public function columnOptionsProvider() : array
1204
    {
1205
        return [
1206
            'string-default'   => [
1207
                '@Column(name="test", type="string", length=10, options={"default"="testing"})',
1208
                ['type' => 'string', 'length' => 10, 'options' => ['default' => 'testing']],
1209
            ],
1210
            'string-fixed'     => [
1211
                '@Column(name="test", type="string", length=10, options={"fixed"=true})',
1212
                ['type' => 'string', 'length' => 10, 'options' => ['fixed' => true]],
1213
            ],
1214
            'string-comment'   => [
1215
                '@Column(name="test", type="string", length=10, options={"comment"="testing"})',
1216
                ['type' => 'string', 'length' => 10, 'options' => ['comment' => 'testing']],
1217
            ],
1218
            'string-collation' => [
1219
                '@Column(name="test", type="string", length=10, options={"collation"="utf8mb4_general_ci"})',
1220
                ['type' => 'string', 'length' => 10, 'options' => ['collation' => 'utf8mb4_general_ci']],
1221
            ],
1222
            'string-check'     => [
1223
                '@Column(name="test", type="string", length=10, options={"check"="CHECK (test IN (""test""))"})',
1224
                ['type' => 'string', 'length' => 10, 'options' => ['check' => 'CHECK (test IN (""test""))']],
1225
            ],
1226
            'string-all'       => [
1227
                '@Column(name="test", type="string", length=10, options={"default"="testing","fixed"=true,"comment"="testing","collation"="utf8mb4_general_ci","check"="CHECK (test IN (""test""))"})',
1228
                [
1229
                    'type' => 'string',
1230
                    'length' => 10,
1231
                    'options' => [
1232
                        'default' => 'testing',
1233
                        'fixed' => true,
1234
                        'comment' => 'testing',
1235
                        'collation' => 'utf8mb4_general_ci',
1236
                        'check' => 'CHECK (test IN (""test""))'
1237
                    ]
1238
                ],
1239
            ],
1240
            'int-default'      => [
1241
                '@Column(name="test", type="integer", options={"default"="10"})',
1242
                ['type' => 'integer', 'options' => ['default' => 10]],
1243
            ],
1244
            'int-unsigned'     => [
1245
                '@Column(name="test", type="integer", options={"unsigned"=true})',
1246
                ['type' => 'integer', 'options' => ['unsigned' => true]],
1247
            ],
1248
            'int-comment'      => [
1249
                '@Column(name="test", type="integer", options={"comment"="testing"})',
1250
                ['type' => 'integer', 'options' => ['comment' => 'testing']],
1251
            ],
1252
            'int-check'        => [
1253
                '@Column(name="test", type="integer", options={"check"="CHECK (test > 5)"})',
1254
                ['type' => 'integer', 'options' => ['check' => 'CHECK (test > 5)']],
1255
            ],
1256
            'int-all'        => [
1257
                '@Column(name="test", type="integer", options={"default"="10","unsigned"=true,"comment"="testing","check"="CHECK (test > 5)"})',
1258
                [
1259
                    'type' => 'integer',
1260
                    'options' => [
1261
                        'default' => 10,
1262
                        'unsigned' => true,
1263
                        'comment' => 'testing',
1264
                        'check' => 'CHECK (test > 5)',
1265
                    ]
1266
                ],
1267
            ],
1268
        ];
1269
    }
1270
}
1271
1272
class EntityGeneratorAuthor {}
1273
class EntityGeneratorComment {}
1274