Passed
Pull Request — 2.6 (#7894)
by
unknown
08:16
created

testGeneratedImmutableEmbeddablesClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 69
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 50
nc 1
nop 0
dl 0
loc 69
rs 9.0909
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
namespace Doctrine\Tests\ORM\Tools;
4
5
use Doctrine\Common\Annotations\AnnotationReader;
6
use Doctrine\Common\Collections\ArrayCollection;
7
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
8
use Doctrine\ORM\Mapping\ClassMetadataFactory;
9
use Doctrine\ORM\Mapping\ClassMetadataInfo;
10
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
11
use Doctrine\ORM\Tools\EntityGenerator;
12
use Doctrine\Tests\Models\DDC2372\DDC2372Admin;
13
use Doctrine\Tests\Models\DDC2372\DDC2372User;
14
use Doctrine\Tests\OrmTestCase;
15
use \ReflectionClass;
16
17
class EntityGeneratorTest extends OrmTestCase
18
{
19
20
    /**
21
     * @var EntityGenerator
22
     */
23
    private $_generator;
24
    private $_tmpDir;
25
    private $_namespace;
26
27
    public function setUp()
28
    {
29
        $this->_namespace = uniqid("doctrine_");
30
        $this->_tmpDir = \sys_get_temp_dir();
31
        \mkdir($this->_tmpDir . \DIRECTORY_SEPARATOR . $this->_namespace);
32
        $this->_generator = new EntityGenerator();
33
        $this->_generator->setAnnotationPrefix("");
34
        $this->_generator->setGenerateAnnotations(true);
35
        $this->_generator->setGenerateStubMethods(true);
36
        $this->_generator->setRegenerateEntityIfExists(false);
37
        $this->_generator->setUpdateEntityIfExists(true);
38
        $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

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

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

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

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

519
        $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...
520
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
521
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
522
        $this->assertEquals($cm->identifier, $metadata->identifier);
523
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
524
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
525
526
        $isbn = $this->newInstance($embeddedMetadata);
0 ignored issues
show
Unused Code introduced by
The assignment to $isbn is dead and can be removed.
Loading history...
527
528
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
529
        $cm->initializeReflection($reflectionService);
530
531
        $driver->loadMetadataForClass($cm->name, $cm);
532
533
        $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

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

1177
        $this->assertRegExp($regex, /** @scrutinizer ignore-type */ $docComment);
Loading history...
1178
        $this->assertEquals(1, preg_match($regex, $docComment, $matches));
1179
        $this->assertEquals($type, $matches[1]);
1180
    }
1181
1182
    /**
1183
     * @param string $type
1184
     * @param \ReflectionMethod $method
1185
     */
1186
    private function assertPhpDocReturnType($type, \ReflectionMethod $method)
1187
    {
1188
        $docComment = $method->getDocComment();
1189
        $regex      = '/@return\s+([\S]+)(\s+.*)$/m';
1190
1191
        $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

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