Passed
Push — 2.7 ( 2785cd...1edfca )
by Benjamin
06:54 queued 11s
created

EntityGeneratorTest::tearDown()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 0
dl 0
loc 10
rs 10
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
use ReflectionClass;
17
18
class EntityGeneratorTest extends OrmTestCase
19
{
20
    use VerifyDeprecations;
21
22
    /**
23
     * @var EntityGenerator
24
     */
25
    private $_generator;
26
    private $_tmpDir;
27
    private $_namespace;
28
29
    public function setUp()
30
    {
31
        $this->_namespace = uniqid("doctrine_");
32
        $this->_tmpDir = \sys_get_temp_dir();
33
        \mkdir($this->_tmpDir . \DIRECTORY_SEPARATOR . $this->_namespace);
34
        $this->_generator = new EntityGenerator();
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\ORM\Tools\EntityGenerator has been deprecated: 2.7 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

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

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

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

486
        $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...
487
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
488
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
489
        $this->assertEquals($cm->identifier, $metadata->identifier);
490
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
491
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
492
        $this->assertEquals($cm->embeddedClasses, $metadata->embeddedClasses);
493
        $this->assertEquals($cm->isEmbeddedClass, $metadata->isEmbeddedClass);
494
495
        $this->assertEquals(ClassMetadataInfo::FETCH_EXTRA_LAZY, $cm->associationMappings['comments']['fetch']);
496
497
        $isbn = $this->newInstance($embeddedMetadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $isbn is dead and can be removed.
Loading history...
498
499
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
500
        $cm->initializeReflection($reflectionService);
501
502
        $driver->loadMetadataForClass($cm->name, $cm);
503
504
        $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

504
        $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...
505
        $this->assertEquals($cm->embeddedClasses, $embeddedMetadata->embeddedClasses);
506
        $this->assertEquals($cm->isEmbeddedClass, $embeddedMetadata->isEmbeddedClass);
507
    }
508
509
    public function testLoadPrefixedMetadata()
510
    {
511
        $this->_generator->setAnnotationPrefix('ORM\\');
512
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
513
        $metadata = $this->generateBookEntityFixture(['isbn' => $embeddedMetadata]);
514
515
        $reader = new AnnotationReader();
516
        $driver = new AnnotationDriver($reader, []);
517
518
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $book is dead and can be removed.
Loading history...
519
520
        $reflectionService = new RuntimeReflectionService();
521
522
        $cm = new ClassMetadataInfo($metadata->name);
523
        $cm->initializeReflection($reflectionService);
524
525
        $driver->loadMetadataForClass($cm->name, $cm);
526
527
        $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

527
        $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...
528
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
529
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
530
        $this->assertEquals($cm->identifier, $metadata->identifier);
531
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
532
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
533
534
        $isbn = $this->newInstance($embeddedMetadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $isbn is dead and can be removed.
Loading history...
535
536
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
537
        $cm->initializeReflection($reflectionService);
538
539
        $driver->loadMetadataForClass($cm->name, $cm);
540
541
        $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

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

1185
        $this->assertRegExp($regex, /** @scrutinizer ignore-type */ $docComment);
Loading history...
1186
        $this->assertEquals(1, preg_match($regex, $docComment, $matches));
1187
        $this->assertEquals($type, $matches[1]);
1188
    }
1189
1190
    /**
1191
     * @param string $type
1192
     * @param \ReflectionMethod $method
1193
     */
1194
    private function assertPhpDocReturnType($type, \ReflectionMethod $method)
1195
    {
1196
        $docComment = $method->getDocComment();
1197
        $regex      = '/@return\s+([\S]+)(\s+.*)$/m';
1198
1199
        $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

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