Failed Conditions
Pull Request — 2.7 (#7901)
by Luís
06:54
created

testDoesNotRegenerateExistingMethodsWithDifferentCase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 16
nc 1
nop 0
dl 0
loc 25
rs 9.7333
c 0
b 0
f 0
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
use Doctrine\Tests\VerifyDeprecations;
16
17
class EntityGeneratorTest extends OrmTestCase
18
{
19
    use VerifyDeprecations;
20
21
    /**
22
     * @var EntityGenerator
23
     */
24
    private $_generator;
25
    private $_tmpDir;
26
    private $_namespace;
27
28
    public function setUp()
29
    {
30
        $this->_namespace = uniqid("doctrine_");
31
        $this->_tmpDir = \sys_get_temp_dir();
32
        \mkdir($this->_tmpDir . \DIRECTORY_SEPARATOR . $this->_namespace);
33
        $this->_generator = new EntityGenerator();
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\ORM\Tools\EntityGenerator has been deprecated: 3.0 This class is being removed from the ORM and won't have any replacement ( Ignorable by Annotation )

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

33
        $this->_generator = /** @scrutinizer ignore-deprecated */ new EntityGenerator();
Loading history...
34
        $this->_generator->setAnnotationPrefix("");
35
        $this->_generator->setGenerateAnnotations(true);
36
        $this->_generator->setGenerateStubMethods(true);
37
        $this->_generator->setRegenerateEntityIfExists(false);
38
        $this->_generator->setUpdateEntityIfExists(true);
39
        $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

39
        $this->_generator->setFieldVisibility(/** @scrutinizer ignore-type */ EntityGenerator::FIELD_VISIBLE_PROTECTED);
Loading history...
40
    }
41
42
    public function tearDown()
43
    {
44
        $ri = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->_tmpDir . '/' . $this->_namespace));
45
        foreach ($ri AS $file) {
46
            /* @var $file \SplFileInfo */
47
            if ($file->isFile()) {
48
                \unlink($file->getPathname());
49
            }
50
        }
51
        rmdir($this->_tmpDir . '/' . $this->_namespace);
52
    }
53
54
    /** @after */
55
    public function ensureTestGeneratedDeprecationMessages() : void
56
    {
57
        $this->assertHasDeprecationMessages();
58
    }
59
60
    /**
61
     * @param ClassMetadataInfo[] $embeddedClasses
62
     *
63
     * @return ClassMetadataInfo
64
     */
65
    public function generateBookEntityFixture(array $embeddedClasses = [])
66
    {
67
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorBook');
68
        $metadata->namespace = $this->_namespace;
69
        $metadata->customRepositoryClassName = $this->_namespace  . '\EntityGeneratorBookRepository';
70
71
        $metadata->table['name'] = 'book';
72
        $metadata->table['uniqueConstraints']['name_uniq'] = ['columns' => ['name']];
73
        $metadata->table['indexes']['status_idx'] = ['columns' => ['status']];
74
        $metadata->mapField(['fieldName' => 'name', 'type' => 'string']);
75
        $metadata->mapField(['fieldName' => 'status', 'type' => 'string', 'options' => ['default' => 'published']]);
76
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
77
        $metadata->mapOneToOne(
78
            ['fieldName' => 'author', 'targetEntity' => EntityGeneratorAuthor::class, 'mappedBy' => 'book']
79
        );
80
        $joinColumns = [
0 ignored issues
show
Unused Code introduced by
The assignment to $joinColumns is dead and can be removed.
Loading history...
81
            ['name' => 'author_id', 'referencedColumnName' => 'id']
82
        ];
83
        $metadata->mapManyToMany(
84
            [
85
            'fieldName' => 'comments',
86
            'targetEntity' => EntityGeneratorComment::class,
87
            'fetch' => ClassMetadataInfo::FETCH_EXTRA_LAZY,
88
            'joinTable' => [
89
                'name' => 'book_comment',
90
                'joinColumns' => [['name' => 'book_id', 'referencedColumnName' => 'id']],
91
                'inverseJoinColumns' => [['name' => 'comment_id', 'referencedColumnName' => 'id']],
92
            ],
93
            ]
94
        );
95
        $metadata->addLifecycleCallback('loading', 'postLoad');
96
        $metadata->addLifecycleCallback('willBeRemoved', 'preRemove');
97
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
98
99
        foreach ($embeddedClasses as $fieldName => $embeddedClass) {
100
            $this->mapNestedEmbedded($fieldName, $metadata, $embeddedClass);
101
            $this->mapEmbedded($fieldName, $metadata, $embeddedClass);
102
        }
103
104
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
105
106
        return $metadata;
107
    }
108
109
    private function generateEntityTypeFixture(array $field)
110
    {
111
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityType');
112
        $metadata->namespace = $this->_namespace;
113
114
        $metadata->table['name'] = 'entity_type';
115
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
116
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
117
118
        $name  = $field['fieldName'];
119
        $type  = $field['dbType'];
120
        $metadata->mapField(['fieldName' => $name, 'type' => $type]);
121
122
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
123
124
        return $metadata;
125
    }
126
127
    /**
128
     * @return ClassMetadataInfo
129
     */
130
    private function generateIsbnEmbeddableFixture(array $embeddedClasses = [], $columnPrefix = null)
131
    {
132
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorIsbn');
133
        $metadata->namespace = $this->_namespace;
134
        $metadata->isEmbeddedClass = true;
135
        $metadata->mapField(['fieldName' => 'prefix', 'type' => 'integer']);
136
        $metadata->mapField(['fieldName' => 'groupNumber', 'type' => 'integer']);
137
        $metadata->mapField(['fieldName' => 'publisherNumber', 'type' => 'integer']);
138
        $metadata->mapField(['fieldName' => 'titleNumber', 'type' => 'integer']);
139
        $metadata->mapField(['fieldName' => 'checkDigit', 'type' => 'integer']);
140
141
        foreach ($embeddedClasses as $fieldName => $embeddedClass) {
142
            $this->mapEmbedded($fieldName, $metadata, $embeddedClass, $columnPrefix);
143
        }
144
145
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
146
147
        return $metadata;
148
    }
149
150
    /**
151
     * @return ClassMetadataInfo
152
     */
153
    private function generateTestEmbeddableFixture()
154
    {
155
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorTestEmbeddable');
156
        $metadata->namespace = $this->_namespace;
157
        $metadata->isEmbeddedClass = true;
158
        $metadata->mapField(['fieldName' => 'field1', 'type' => 'integer']);
159
        $metadata->mapField(['fieldName' => 'field2', 'type' => 'integer', 'nullable' => true]);
160
        $metadata->mapField(['fieldName' => 'field3', 'type' => 'datetime']);
161
        $metadata->mapField(['fieldName' => 'field4', 'type' => 'datetime', 'nullable' => true]);
162
163
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
164
165
        return $metadata;
166
    }
167
168
    /**
169
     * @param string            $fieldName
170
     * @param ClassMetadataInfo $classMetadata
171
     * @param ClassMetadataInfo $embeddableMetadata
172
     * @param string|null       $columnPrefix
173
     */
174
    private function mapEmbedded(
175
        $fieldName,
176
        ClassMetadataInfo $classMetadata,
177
        ClassMetadataInfo $embeddableMetadata,
178
        $columnPrefix = false
179
    ) {
180
        $classMetadata->mapEmbedded(
181
            ['fieldName' => $fieldName, 'class' => $embeddableMetadata->name, 'columnPrefix' => $columnPrefix]
182
        );
183
    }
184
185
    /**
186
     * @param string            $fieldName
187
     * @param ClassMetadataInfo $classMetadata
188
     * @param ClassMetadataInfo $embeddableMetadata
189
     */
190
    private function mapNestedEmbedded(
191
        $fieldName,
192
        ClassMetadataInfo $classMetadata,
193
        ClassMetadataInfo $embeddableMetadata
194
    ) {
195
        foreach ($embeddableMetadata->embeddedClasses as $property => $embeddableClass) {
196
            $classMetadata->mapEmbedded(
197
                [
198
                'fieldName' => $fieldName . '.' . $property,
199
                'class' => $embeddableClass['class'],
200
                'columnPrefix' => $embeddableClass['columnPrefix'],
201
                'declaredField' => $embeddableClass['declaredField']
202
                        ? $fieldName . '.' . $embeddableClass['declaredField']
203
                        : $fieldName,
204
                'originalField' => $embeddableClass['originalField'] ?: $property,
205
                ]
206
            );
207
        }
208
    }
209
210
    /**
211
     * @param ClassMetadataInfo $metadata
212
     */
213
    private function loadEntityClass(ClassMetadataInfo $metadata)
214
    {
215
        $className = basename(str_replace('\\', '/', $metadata->name));
216
        $path = $this->_tmpDir . '/' . $this->_namespace . '/' . $className . '.php';
217
218
        $this->assertFileExists($path);
219
220
        require_once $path;
221
    }
222
223
    /**
224
     * @param  ClassMetadataInfo $metadata
225
     *
226
     * @return mixed An instance of the given metadata's class.
227
     */
228
    public function newInstance($metadata)
229
    {
230
        $this->loadEntityClass($metadata);
231
232
        return new $metadata->name;
233
    }
234
235
    /**
236
     * @group GH-6314
237
     */
238
    public function testEmbeddedEntityWithNamedColumnPrefix()
239
    {
240
        $columnPrefix = 'GH6314Prefix_';
241
        $testMetadata = $this->generateTestEmbeddableFixture();
242
        $isbnMetadata = $this->generateIsbnEmbeddableFixture(['testEmbedded' => $testMetadata], $columnPrefix);
243
        $isbnEntity = $this->newInstance($isbnMetadata);
244
        $refClass = new \ReflectionClass($isbnEntity);
245
        self::assertTrue($refClass->hasProperty('testEmbedded'));
246
247
        $docComment = $refClass->getProperty('testEmbedded')->getDocComment();
248
        $needle = sprintf('@Embedded(class="%s", columnPrefix="%s")', $testMetadata->name, $columnPrefix);
249
        self::assertContains($needle, $docComment);
250
    }
251
252
    /**
253
     * @group GH-6314
254
     */
255
    public function testEmbeddedEntityWithoutColumnPrefix()
256
    {
257
        $testMetadata = $this->generateTestEmbeddableFixture();
258
        $isbnMetadata = $this->generateIsbnEmbeddableFixture(['testEmbedded' => $testMetadata], false);
259
        $isbnEntity = $this->newInstance($isbnMetadata);
260
        $refClass = new \ReflectionClass($isbnEntity);
261
        self::assertTrue($refClass->hasProperty('testEmbedded'));
262
263
        $docComment = $refClass->getProperty('testEmbedded')->getDocComment();
264
        $needle = sprintf('@Embedded(class="%s", columnPrefix=false)', $testMetadata->name);
265
        self::assertContains($needle, $docComment);
266
    }
267
268
    public function testGeneratedEntityClass()
269
    {
270
        $testMetadata = $this->generateTestEmbeddableFixture();
271
        $isbnMetadata = $this->generateIsbnEmbeddableFixture(['test' => $testMetadata]);
272
        $metadata = $this->generateBookEntityFixture(['isbn' => $isbnMetadata]);
273
274
        $book = $this->newInstance($metadata);
275
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
276
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', '__construct'), "EntityGeneratorBook::__construct() missing.");
277
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getId'), "EntityGeneratorBook::getId() missing.");
278
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setName'), "EntityGeneratorBook::setName() missing.");
279
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getName'), "EntityGeneratorBook::getName() missing.");
280
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setStatus'), "EntityGeneratorBook::setStatus() missing.");
281
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getStatus'), "EntityGeneratorBook::getStatus() missing.");
282
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setAuthor'), "EntityGeneratorBook::setAuthor() missing.");
283
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getAuthor'), "EntityGeneratorBook::getAuthor() missing.");
284
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getComments'), "EntityGeneratorBook::getComments() missing.");
285
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'addComment'), "EntityGeneratorBook::addComment() missing.");
286
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'removeComment'), "EntityGeneratorBook::removeComment() missing.");
287
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setIsbn'), "EntityGeneratorBook::setIsbn() missing.");
288
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getIsbn'), "EntityGeneratorBook::getIsbn() missing.");
289
290
        $reflClass = new \ReflectionClass($metadata->name);
291
292
        $this->assertCount(6, $reflClass->getProperties());
293
        $this->assertCount(15, $reflClass->getMethods());
294
295
        $this->assertEquals('published', $book->getStatus());
296
297
        $book->setName('Jonathan H. Wage');
298
        $this->assertEquals('Jonathan H. Wage', $book->getName());
299
300
        $reflMethod = new \ReflectionMethod($metadata->name, 'addComment');
301
        $addCommentParameters = $reflMethod->getParameters();
302
        $this->assertEquals('comment', $addCommentParameters[0]->getName());
303
304
        $reflMethod = new \ReflectionMethod($metadata->name, 'removeComment');
305
        $removeCommentParameters = $reflMethod->getParameters();
306
        $this->assertEquals('comment', $removeCommentParameters[0]->getName());
307
308
        $author = new EntityGeneratorAuthor();
309
        $book->setAuthor($author);
310
        $this->assertEquals($author, $book->getAuthor());
311
312
        $comment = new EntityGeneratorComment();
313
        $this->assertInstanceOf($metadata->name, $book->addComment($comment));
314
        $this->assertInstanceOf(ArrayCollection::class, $book->getComments());
315
        $this->assertEquals(new ArrayCollection([$comment]), $book->getComments());
316
        $this->assertInternalType('boolean', $book->removeComment($comment));
0 ignored issues
show
Deprecated Code introduced by
The function PHPUnit\Framework\Assert::assertInternalType() has been deprecated: https://github.com/sebastianbergmann/phpunit/issues/3369 ( Ignorable by Annotation )

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

316
        /** @scrutinizer ignore-deprecated */ $this->assertInternalType('boolean', $book->removeComment($comment));

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

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

Loading history...
317
        $this->assertEquals(new ArrayCollection([]), $book->getComments());
318
319
        $this->newInstance($isbnMetadata);
320
        $isbn = new $isbnMetadata->name();
321
322
        $book->setIsbn($isbn);
323
        $this->assertSame($isbn, $book->getIsbn());
324
325
        $reflMethod = new \ReflectionMethod($metadata->name, 'setIsbn');
326
        $reflParameters = $reflMethod->getParameters();
327
        $this->assertEquals($isbnMetadata->name, $reflParameters[0]->getClass()->name);
328
    }
329
330
    public function testEntityUpdatingWorks()
331
    {
332
        $metadata = $this->generateBookEntityFixture(['isbn' => $this->generateIsbnEmbeddableFixture()]);
333
334
        $metadata->mapField(['fieldName' => 'test', 'type' => 'string']);
335
336
        $testEmbeddableMetadata = $this->generateTestEmbeddableFixture();
337
        $this->mapEmbedded('testEmbedded', $metadata, $testEmbeddableMetadata);
338
339
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
340
341
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
342
343
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $book is dead and can be removed.
Loading history...
344
        $reflClass = new \ReflectionClass($metadata->name);
345
346
        $this->assertTrue($reflClass->hasProperty('name'), "Regenerating keeps property 'name'.");
347
        $this->assertTrue($reflClass->hasProperty('status'), "Regenerating keeps property 'status'.");
348
        $this->assertTrue($reflClass->hasProperty('id'), "Regenerating keeps property 'id'.");
349
        $this->assertTrue($reflClass->hasProperty('isbn'), "Regenerating keeps property 'isbn'.");
350
351
        $this->assertTrue($reflClass->hasProperty('test'), "Check for property test failed.");
352
        $this->assertTrue($reflClass->getProperty('test')->isProtected(), "Check for protected property test failed.");
353
        $this->assertTrue($reflClass->hasProperty('testEmbedded'), "Check for property testEmbedded failed.");
354
        $this->assertTrue($reflClass->getProperty('testEmbedded')->isProtected(), "Check for protected property testEmbedded failed.");
355
        $this->assertTrue($reflClass->hasMethod('getTest'), "Check for method 'getTest' failed.");
356
        $this->assertTrue($reflClass->getMethod('getTest')->isPublic(), "Check for public visibility of method 'getTest' failed.");
357
        $this->assertTrue($reflClass->hasMethod('setTest'), "Check for method 'setTest' failed.");
358
        $this->assertTrue($reflClass->getMethod('setTest')->isPublic(), "Check for public visibility of method 'setTest' failed.");
359
        $this->assertTrue($reflClass->hasMethod('getTestEmbedded'), "Check for method 'getTestEmbedded' failed.");
360
        $this->assertTrue(
361
            $reflClass->getMethod('getTestEmbedded')->isPublic(),
362
            "Check for public visibility of method 'getTestEmbedded' failed."
363
        );
364
        $this->assertTrue($reflClass->hasMethod('setTestEmbedded'), "Check for method 'setTestEmbedded' failed.");
365
        $this->assertTrue(
366
            $reflClass->getMethod('setTestEmbedded')->isPublic(),
367
            "Check for public visibility of method 'setTestEmbedded' failed."
368
        );
369
    }
370
371
    /**
372
     * @group DDC-3152
373
     */
374
    public function testDoesNotRegenerateExistingMethodsWithDifferentCase()
375
    {
376
        $metadata = $this->generateBookEntityFixture(['isbn' => $this->generateIsbnEmbeddableFixture()]);
377
378
        // Workaround to change existing fields case (just to simulate the use case)
379
        $metadata->fieldMappings['status']['fieldName'] = 'STATUS';
380
        $metadata->embeddedClasses['ISBN'] = $metadata->embeddedClasses['isbn'];
381
        unset($metadata->embeddedClasses['isbn']);
382
383
        // Should not throw a PHP fatal error
384
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
385
386
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
387
388
        $this->newInstance($metadata);
389
        $reflClass = new \ReflectionClass($metadata->name);
390
391
        $this->assertTrue($reflClass->hasProperty('status'));
392
        $this->assertTrue($reflClass->hasProperty('STATUS'));
393
        $this->assertTrue($reflClass->hasProperty('isbn'));
394
        $this->assertTrue($reflClass->hasProperty('ISBN'));
395
        $this->assertTrue($reflClass->hasMethod('getStatus'));
396
        $this->assertTrue($reflClass->hasMethod('setStatus'));
397
        $this->assertTrue($reflClass->hasMethod('getIsbn'));
398
        $this->assertTrue($reflClass->hasMethod('setIsbn'));
399
    }
400
401
    /**
402
     * @group DDC-2121
403
     */
404
    public function testMethodDocBlockShouldStartWithBackSlash()
405
    {
406
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
407
        $metadata = $this->generateBookEntityFixture(['isbn' => $embeddedMetadata]);
408
        $book     = $this->newInstance($metadata);
409
410
        $this->assertPhpDocVarType('\Doctrine\Common\Collections\Collection', new \ReflectionProperty($book, 'comments'));
411
        $this->assertPhpDocReturnType('\Doctrine\Common\Collections\Collection', new \ReflectionMethod($book, 'getComments'));
412
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorComment', new \ReflectionMethod($book, 'addComment'));
413
        $this->assertPhpDocReturnType('EntityGeneratorBook', new \ReflectionMethod($book, 'addComment'));
414
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorComment', new \ReflectionMethod($book, 'removeComment'));
415
        $this->assertPhpDocReturnType('boolean', new \ReflectionMethod($book, 'removeComment'));
416
417
        $this->assertPhpDocVarType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', new \ReflectionProperty($book, 'author'));
418
        $this->assertPhpDocReturnType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor|null', new \ReflectionMethod($book, 'getAuthor'));
419
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor|null', new \ReflectionMethod($book, 'setAuthor'));
420
421
        $expectedClassName = '\\' . $embeddedMetadata->name;
422
        $this->assertPhpDocVarType($expectedClassName, new \ReflectionProperty($book, 'isbn'));
423
        $this->assertPhpDocReturnType($expectedClassName, new \ReflectionMethod($book, 'getIsbn'));
424
        $this->assertPhpDocParamType($expectedClassName, new \ReflectionMethod($book, 'setIsbn'));
425
    }
426
427
    public function testEntityExtendsStdClass()
428
    {
429
        $this->_generator->setClassToExtend('stdClass');
430
        $metadata = $this->generateBookEntityFixture();
431
432
        $book = $this->newInstance($metadata);
433
        $this->assertInstanceOf('stdClass', $book);
434
435
        $metadata = $this->generateIsbnEmbeddableFixture();
436
        $isbn = $this->newInstance($metadata);
437
        $this->assertInstanceOf('stdClass', $isbn);
438
    }
439
440
    public function testLifecycleCallbacks()
441
    {
442
        $metadata = $this->generateBookEntityFixture();
443
444
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $book is dead and can be removed.
Loading history...
445
        $reflClass = new \ReflectionClass($metadata->name);
446
447
        $this->assertTrue($reflClass->hasMethod('loading'), "Check for postLoad lifecycle callback.");
448
        $this->assertTrue($reflClass->hasMethod('willBeRemoved'), "Check for preRemove lifecycle callback.");
449
    }
450
451
    public function testLoadMetadata()
452
    {
453
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
454
        $metadata = $this->generateBookEntityFixture(['isbn' => $embeddedMetadata]);
455
456
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $book is dead and can be removed.
Loading history...
457
458
        $reflectionService = new RuntimeReflectionService();
459
460
        $cm = new ClassMetadataInfo($metadata->name);
461
        $cm->initializeReflection($reflectionService);
462
463
        $driver = $this->createAnnotationDriver();
464
        $driver->loadMetadataForClass($cm->name, $cm);
465
466
        $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

466
        $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...
467
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
468
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
469
        $this->assertEquals($cm->identifier, $metadata->identifier);
470
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
471
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
472
        $this->assertEquals($cm->embeddedClasses, $metadata->embeddedClasses);
473
        $this->assertEquals($cm->isEmbeddedClass, $metadata->isEmbeddedClass);
474
475
        $this->assertEquals(ClassMetadataInfo::FETCH_EXTRA_LAZY, $cm->associationMappings['comments']['fetch']);
476
477
        $isbn = $this->newInstance($embeddedMetadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $isbn is dead and can be removed.
Loading history...
478
479
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
480
        $cm->initializeReflection($reflectionService);
481
482
        $driver->loadMetadataForClass($cm->name, $cm);
483
484
        $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

484
        $this->assertEquals($cm->columnNames, /** @scrutinizer ignore-deprecated */ $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...
485
        $this->assertEquals($cm->embeddedClasses, $embeddedMetadata->embeddedClasses);
486
        $this->assertEquals($cm->isEmbeddedClass, $embeddedMetadata->isEmbeddedClass);
487
    }
488
489
    public function testLoadPrefixedMetadata()
490
    {
491
        $this->_generator->setAnnotationPrefix('ORM\\');
492
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
493
        $metadata = $this->generateBookEntityFixture(['isbn' => $embeddedMetadata]);
494
495
        $reader = new AnnotationReader();
496
        $driver = new AnnotationDriver($reader, []);
497
498
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $book is dead and can be removed.
Loading history...
499
500
        $reflectionService = new RuntimeReflectionService();
501
502
        $cm = new ClassMetadataInfo($metadata->name);
503
        $cm->initializeReflection($reflectionService);
504
505
        $driver->loadMetadataForClass($cm->name, $cm);
506
507
        $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

507
        $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...
508
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
509
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
510
        $this->assertEquals($cm->identifier, $metadata->identifier);
511
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
512
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
513
514
        $isbn = $this->newInstance($embeddedMetadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $isbn is dead and can be removed.
Loading history...
515
516
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
517
        $cm->initializeReflection($reflectionService);
518
519
        $driver->loadMetadataForClass($cm->name, $cm);
520
521
        $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

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

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

1165
        $this->assertRegExp($regex, /** @scrutinizer ignore-type */ $docComment);
Loading history...
1166
        $this->assertEquals(1, preg_match($regex, $docComment, $matches));
1167
        $this->assertEquals($type, $matches[1]);
1168
    }
1169
1170
    /**
1171
     * @param string $type
1172
     * @param \ReflectionMethod $method
1173
     */
1174
    private function assertPhpDocReturnType($type, \ReflectionMethod $method)
1175
    {
1176
        $docComment = $method->getDocComment();
1177
        $regex      = '/@return\s+([\S]+)(\s+.*)$/m';
1178
1179
        $this->assertRegExp($regex, $docComment);
0 ignored issues
show
Bug introduced by
It seems like $docComment can also be of type boolean; however, parameter $string of PHPUnit\Framework\Assert::assertRegExp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1179
        $this->assertRegExp($regex, /** @scrutinizer ignore-type */ $docComment);
Loading history...
1180
        $this->assertEquals(1, preg_match($regex, $docComment, $matches));
1181
        $this->assertEquals($type, $matches[1]);
1182
    }
1183
1184
    /**
1185
     * @param string $type
1186
     * @param \ReflectionProperty $method
1187
     */
1188
    private function assertPhpDocParamType($type, \ReflectionMethod $method)
1189
    {
1190
        $this->assertEquals(1, preg_match('/@param\s+([^\s]+)/', $method->getDocComment(), $matches));
1191
        $this->assertEquals($type, $matches[1]);
1192
    }
1193
1194
    /**
1195
     * @group 6703
1196
     *
1197
     * @dataProvider columnOptionsProvider
1198
     */
1199
    public function testOptionsAreGeneratedProperly(string $expectedAnnotation, array $fieldConfiguration) : void
1200
    {
1201
        $metadata               = new ClassMetadataInfo($this->_namespace . '\GH6703Options');
1202
        $metadata->namespace    = $this->_namespace;
1203
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
1204
        $metadata->mapField(['fieldName' => 'test'] + $fieldConfiguration);
1205
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
1206
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
1207
1208
        $filename = $this->_tmpDir . DIRECTORY_SEPARATOR . $this->_namespace . DIRECTORY_SEPARATOR . 'GH6703Options.php';
1209
1210
        self::assertFileExists($filename);
1211
        require_once $filename;
1212
1213
        $property   = new \ReflectionProperty($metadata->name, 'test');
1214
        $docComment = $property->getDocComment();
1215
1216
        self::assertContains($expectedAnnotation, $docComment);
1217
    }
1218
1219
    public function columnOptionsProvider() : array
1220
    {
1221
        return [
1222
            'string-default'   => [
1223
                '@Column(name="test", type="string", length=10, options={"default"="testing"})',
1224
                ['type' => 'string', 'length' => 10, 'options' => ['default' => 'testing']],
1225
            ],
1226
            'string-fixed'     => [
1227
                '@Column(name="test", type="string", length=10, options={"fixed"=true})',
1228
                ['type' => 'string', 'length' => 10, 'options' => ['fixed' => true]],
1229
            ],
1230
            'string-comment'   => [
1231
                '@Column(name="test", type="string", length=10, options={"comment"="testing"})',
1232
                ['type' => 'string', 'length' => 10, 'options' => ['comment' => 'testing']],
1233
            ],
1234
            'string-comment-quote'   => [
1235
                '@Column(name="test", type="string", length=10, options={"comment"="testing ""quotes"""})',
1236
                ['type' => 'string', 'length' => 10, 'options' => ['comment' => 'testing "quotes"']],
1237
            ],
1238
            'string-collation' => [
1239
                '@Column(name="test", type="string", length=10, options={"collation"="utf8mb4_general_ci"})',
1240
                ['type' => 'string', 'length' => 10, 'options' => ['collation' => 'utf8mb4_general_ci']],
1241
            ],
1242
            'string-check'     => [
1243
                '@Column(name="test", type="string", length=10, options={"check"="CHECK (test IN (""test""))"})',
1244
                ['type' => 'string', 'length' => 10, 'options' => ['check' => 'CHECK (test IN (""test""))']],
1245
            ],
1246
            'string-all'       => [
1247
                '@Column(name="test", type="string", length=10, options={"default"="testing","fixed"=true,"comment"="testing","collation"="utf8mb4_general_ci","check"="CHECK (test IN (""test""))"})',
1248
                [
1249
                    'type' => 'string',
1250
                    'length' => 10,
1251
                    'options' => [
1252
                        'default' => 'testing',
1253
                        'fixed' => true,
1254
                        'comment' => 'testing',
1255
                        'collation' => 'utf8mb4_general_ci',
1256
                        'check' => 'CHECK (test IN (""test""))'
1257
                    ]
1258
                ],
1259
            ],
1260
            'int-default'      => [
1261
                '@Column(name="test", type="integer", options={"default"="10"})',
1262
                ['type' => 'integer', 'options' => ['default' => 10]],
1263
            ],
1264
            'int-unsigned'     => [
1265
                '@Column(name="test", type="integer", options={"unsigned"=true})',
1266
                ['type' => 'integer', 'options' => ['unsigned' => true]],
1267
            ],
1268
            'int-comment'      => [
1269
                '@Column(name="test", type="integer", options={"comment"="testing"})',
1270
                ['type' => 'integer', 'options' => ['comment' => 'testing']],
1271
            ],
1272
            'int-check'        => [
1273
                '@Column(name="test", type="integer", options={"check"="CHECK (test > 5)"})',
1274
                ['type' => 'integer', 'options' => ['check' => 'CHECK (test > 5)']],
1275
            ],
1276
            'int-all'        => [
1277
                '@Column(name="test", type="integer", options={"default"="10","unsigned"=true,"comment"="testing","check"="CHECK (test > 5)"})',
1278
                [
1279
                    'type' => 'integer',
1280
                    'options' => [
1281
                        'default' => 10,
1282
                        'unsigned' => true,
1283
                        'comment' => 'testing',
1284
                        'check' => 'CHECK (test > 5)',
1285
                    ]
1286
                ],
1287
            ],
1288
        ];
1289
    }
1290
}
1291
1292
class EntityGeneratorAuthor {}
1293
class EntityGeneratorComment {}
1294