Failed Conditions
Push — master ( 2ade86...13f838 )
by Jonathan
18s
created

Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php (8 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Doctrine\Tests\ORM\Tools;
4
5
use Doctrine\Common\Annotations\AnnotationReader;
6
use Doctrine\Common\Collections\ArrayCollection;
7
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
8
use Doctrine\ORM\Mapping\ClassMetadataFactory;
9
use Doctrine\ORM\Mapping\ClassMetadataInfo;
10
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
11
use Doctrine\ORM\Tools\EntityGenerator;
12
use Doctrine\Tests\Models\DDC2372\DDC2372Admin;
13
use Doctrine\Tests\Models\DDC2372\DDC2372User;
14
use Doctrine\Tests\OrmTestCase;
15
16
class EntityGeneratorTest extends OrmTestCase
17
{
18
19
    /**
20
     * @var EntityGenerator
21
     */
22
    private $_generator;
23
    private $_tmpDir;
24
    private $_namespace;
25
26 View Code Duplication
    public function setUp()
27
    {
28
        $this->_namespace = uniqid("doctrine_");
29
        $this->_tmpDir = \sys_get_temp_dir();
30
        \mkdir($this->_tmpDir . \DIRECTORY_SEPARATOR . $this->_namespace);
31
        $this->_generator = new EntityGenerator();
32
        $this->_generator->setAnnotationPrefix("");
33
        $this->_generator->setGenerateAnnotations(true);
34
        $this->_generator->setGenerateStubMethods(true);
35
        $this->_generator->setRegenerateEntityIfExists(false);
36
        $this->_generator->setUpdateEntityIfExists(true);
37
        $this->_generator->setFieldVisibility(EntityGenerator::FIELD_VISIBLE_PROTECTED);
38
    }
39
40
    public function tearDown()
41
    {
42
        $ri = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->_tmpDir . '/' . $this->_namespace));
43
        foreach ($ri AS $file) {
44
            /* @var $file \SplFileInfo */
45
            if ($file->isFile()) {
46
                \unlink($file->getPathname());
47
            }
48
        }
49
        rmdir($this->_tmpDir . '/' . $this->_namespace);
50
    }
51
52
    /**
53
     * @param ClassMetadataInfo[] $embeddedClasses
54
     *
55
     * @return ClassMetadataInfo
56
     */
57
    public function generateBookEntityFixture(array $embeddedClasses = [])
58
    {
59
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorBook');
60
        $metadata->namespace = $this->_namespace;
61
        $metadata->customRepositoryClassName = $this->_namespace  . '\EntityGeneratorBookRepository';
62
63
        $metadata->table['name'] = 'book';
64
        $metadata->table['uniqueConstraints']['name_uniq'] = ['columns' => ['name']];
65
        $metadata->table['indexes']['status_idx'] = ['columns' => ['status']];
66
        $metadata->mapField(['fieldName' => 'name', 'type' => 'string']);
67
        $metadata->mapField(['fieldName' => 'status', 'type' => 'string', 'options' => ['default' => 'published']]);
68
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
69
        $metadata->mapOneToOne(
70
            ['fieldName' => 'author', 'targetEntity' => EntityGeneratorAuthor::class, 'mappedBy' => 'book']
71
        );
72
        $joinColumns = [
73
            ['name' => 'author_id', 'referencedColumnName' => 'id']
74
        ];
75
        $metadata->mapManyToMany(
76
            [
77
            'fieldName' => 'comments',
78
            'targetEntity' => EntityGeneratorComment::class,
79
            'fetch' => ClassMetadataInfo::FETCH_EXTRA_LAZY,
80
            'joinTable' => [
81
                'name' => 'book_comment',
82
                'joinColumns' => [['name' => 'book_id', 'referencedColumnName' => 'id']],
83
                'inverseJoinColumns' => [['name' => 'comment_id', 'referencedColumnName' => 'id']],
84
            ],
85
            ]
86
        );
87
        $metadata->addLifecycleCallback('loading', 'postLoad');
88
        $metadata->addLifecycleCallback('willBeRemoved', 'preRemove');
89
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
90
91
        foreach ($embeddedClasses as $fieldName => $embeddedClass) {
92
            $this->mapNestedEmbedded($fieldName, $metadata, $embeddedClass);
93
            $this->mapEmbedded($fieldName, $metadata, $embeddedClass);
94
        }
95
96
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
97
98
        return $metadata;
99
    }
100
101
    private function generateEntityTypeFixture(array $field)
102
    {
103
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityType');
104
        $metadata->namespace = $this->_namespace;
105
106
        $metadata->table['name'] = 'entity_type';
107
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
108
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
109
110
        $name  = $field['fieldName'];
111
        $type  = $field['dbType'];
112
        $metadata->mapField(['fieldName' => $name, 'type' => $type]);
113
114
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
115
116
        return $metadata;
117
    }
118
119
    /**
120
     * @return ClassMetadataInfo
121
     */
122
    private function generateIsbnEmbeddableFixture(array $embeddedClasses = [], $columnPrefix = null)
123
    {
124
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorIsbn');
125
        $metadata->namespace = $this->_namespace;
126
        $metadata->isEmbeddedClass = true;
127
        $metadata->mapField(['fieldName' => 'prefix', 'type' => 'integer']);
128
        $metadata->mapField(['fieldName' => 'groupNumber', 'type' => 'integer']);
129
        $metadata->mapField(['fieldName' => 'publisherNumber', 'type' => 'integer']);
130
        $metadata->mapField(['fieldName' => 'titleNumber', 'type' => 'integer']);
131
        $metadata->mapField(['fieldName' => 'checkDigit', 'type' => 'integer']);
132
133
        foreach ($embeddedClasses as $fieldName => $embeddedClass) {
134
            $this->mapEmbedded($fieldName, $metadata, $embeddedClass, $columnPrefix);
135
        }
136
137
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
138
139
        return $metadata;
140
    }
141
142
    /**
143
     * @return ClassMetadataInfo
144
     */
145
    private function generateTestEmbeddableFixture()
146
    {
147
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorTestEmbeddable');
148
        $metadata->namespace = $this->_namespace;
149
        $metadata->isEmbeddedClass = true;
150
        $metadata->mapField(['fieldName' => 'field1', 'type' => 'integer']);
151
        $metadata->mapField(['fieldName' => 'field2', 'type' => 'integer', 'nullable' => true]);
152
        $metadata->mapField(['fieldName' => 'field3', 'type' => 'datetime']);
153
        $metadata->mapField(['fieldName' => 'field4', 'type' => 'datetime', 'nullable' => true]);
154
155
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
156
157
        return $metadata;
158
    }
159
160
    /**
161
     * @param string            $fieldName
162
     * @param ClassMetadataInfo $classMetadata
163
     * @param ClassMetadataInfo $embeddableMetadata
164
     * @param string|null       $columnPrefix
165
     */
166
    private function mapEmbedded(
167
        $fieldName,
168
        ClassMetadataInfo $classMetadata,
169
        ClassMetadataInfo $embeddableMetadata,
170
        $columnPrefix = false
171
    ) {
172
        $classMetadata->mapEmbedded(
173
            ['fieldName' => $fieldName, 'class' => $embeddableMetadata->name, 'columnPrefix' => $columnPrefix]
174
        );
175
    }
176
177
    /**
178
     * @param string            $fieldName
179
     * @param ClassMetadataInfo $classMetadata
180
     * @param ClassMetadataInfo $embeddableMetadata
181
     */
182
    private function mapNestedEmbedded(
183
        $fieldName,
184
        ClassMetadataInfo $classMetadata,
185
        ClassMetadataInfo $embeddableMetadata
186
    ) {
187
        foreach ($embeddableMetadata->embeddedClasses as $property => $embeddableClass) {
188
            $classMetadata->mapEmbedded(
189
                [
190
                'fieldName' => $fieldName . '.' . $property,
191
                'class' => $embeddableClass['class'],
192
                'columnPrefix' => $embeddableClass['columnPrefix'],
193
                'declaredField' => $embeddableClass['declaredField']
194
                        ? $fieldName . '.' . $embeddableClass['declaredField']
195
                        : $fieldName,
196
                'originalField' => $embeddableClass['originalField'] ?: $property,
197
                ]
198
            );
199
        }
200
    }
201
202
    /**
203
     * @param ClassMetadataInfo $metadata
204
     */
205
    private function loadEntityClass(ClassMetadataInfo $metadata)
206
    {
207
        $className = basename(str_replace('\\', '/', $metadata->name));
208
        $path = $this->_tmpDir . '/' . $this->_namespace . '/' . $className . '.php';
209
210
        $this->assertFileExists($path);
211
212
        require_once $path;
213
    }
214
215
    /**
216
     * @param  ClassMetadataInfo $metadata
217
     *
218
     * @return mixed An instance of the given metadata's class.
219
     */
220
    public function newInstance($metadata)
221
    {
222
        $this->loadEntityClass($metadata);
223
224
        return new $metadata->name;
225
    }
226
227
    /**
228
     * @group GH-6314
229
     */
230
    public function testEmbeddedEntityWithNamedColumnPrefix()
231
    {
232
        $columnPrefix = 'GH6314Prefix_';
233
        $testMetadata = $this->generateTestEmbeddableFixture();
234
        $isbnMetadata = $this->generateIsbnEmbeddableFixture(['testEmbedded' => $testMetadata], $columnPrefix);
235
        $isbnEntity = $this->newInstance($isbnMetadata);
236
        $refClass = new \ReflectionClass($isbnEntity);
237
        self::assertTrue($refClass->hasProperty('testEmbedded'));
238
239
        $docComment = $refClass->getProperty('testEmbedded')->getDocComment();
240
        $needle = sprintf('@Embedded(class="%s", columnPrefix="%s")', $testMetadata->name, $columnPrefix);
241
        self::assertContains($needle, $docComment);
242
    }
243
244
    /**
245
     * @group GH-6314
246
     */
247
    public function testEmbeddedEntityWithoutColumnPrefix()
248
    {
249
        $testMetadata = $this->generateTestEmbeddableFixture();
250
        $isbnMetadata = $this->generateIsbnEmbeddableFixture(['testEmbedded' => $testMetadata], false);
251
        $isbnEntity = $this->newInstance($isbnMetadata);
252
        $refClass = new \ReflectionClass($isbnEntity);
253
        self::assertTrue($refClass->hasProperty('testEmbedded'));
254
255
        $docComment = $refClass->getProperty('testEmbedded')->getDocComment();
256
        $needle = sprintf('@Embedded(class="%s", columnPrefix=false)', $testMetadata->name);
257
        self::assertContains($needle, $docComment);
258
    }
259
260
    public function testGeneratedEntityClass()
261
    {
262
        $testMetadata = $this->generateTestEmbeddableFixture();
263
        $isbnMetadata = $this->generateIsbnEmbeddableFixture(['test' => $testMetadata]);
264
        $metadata = $this->generateBookEntityFixture(['isbn' => $isbnMetadata]);
265
266
        $book = $this->newInstance($metadata);
267
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
268
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', '__construct'), "EntityGeneratorBook::__construct() missing.");
269
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getId'), "EntityGeneratorBook::getId() missing.");
270
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setName'), "EntityGeneratorBook::setName() missing.");
271
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getName'), "EntityGeneratorBook::getName() missing.");
272
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setStatus'), "EntityGeneratorBook::setStatus() missing.");
273
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getStatus'), "EntityGeneratorBook::getStatus() missing.");
274
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setAuthor'), "EntityGeneratorBook::setAuthor() missing.");
275
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getAuthor'), "EntityGeneratorBook::getAuthor() missing.");
276
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getComments'), "EntityGeneratorBook::getComments() missing.");
277
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'addComment'), "EntityGeneratorBook::addComment() missing.");
278
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'removeComment'), "EntityGeneratorBook::removeComment() missing.");
279
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setIsbn'), "EntityGeneratorBook::setIsbn() missing.");
280
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getIsbn'), "EntityGeneratorBook::getIsbn() missing.");
281
282
        $reflClass = new \ReflectionClass($metadata->name);
283
284
        $this->assertCount(6, $reflClass->getProperties());
285
        $this->assertCount(15, $reflClass->getMethods());
286
287
        $this->assertEquals('published', $book->getStatus());
288
289
        $book->setName('Jonathan H. Wage');
290
        $this->assertEquals('Jonathan H. Wage', $book->getName());
291
292
        $reflMethod = new \ReflectionMethod($metadata->name, 'addComment');
293
        $addCommentParameters = $reflMethod->getParameters();
294
        $this->assertEquals('comment', $addCommentParameters[0]->getName());
295
296
        $reflMethod = new \ReflectionMethod($metadata->name, 'removeComment');
297
        $removeCommentParameters = $reflMethod->getParameters();
298
        $this->assertEquals('comment', $removeCommentParameters[0]->getName());
299
300
        $author = new EntityGeneratorAuthor();
301
        $book->setAuthor($author);
302
        $this->assertEquals($author, $book->getAuthor());
303
304
        $comment = new EntityGeneratorComment();
305
        $this->assertInstanceOf($metadata->name, $book->addComment($comment));
306
        $this->assertInstanceOf(ArrayCollection::class, $book->getComments());
307
        $this->assertEquals(new ArrayCollection([$comment]), $book->getComments());
308
        $this->assertInternalType('boolean', $book->removeComment($comment));
309
        $this->assertEquals(new ArrayCollection([]), $book->getComments());
310
311
        $this->newInstance($isbnMetadata);
312
        $isbn = new $isbnMetadata->name();
313
314
        $book->setIsbn($isbn);
315
        $this->assertSame($isbn, $book->getIsbn());
316
317
        $reflMethod = new \ReflectionMethod($metadata->name, 'setIsbn');
318
        $reflParameters = $reflMethod->getParameters();
319
        $this->assertEquals($isbnMetadata->name, $reflParameters[0]->getClass()->name);
320
    }
321
322
    public function testEntityUpdatingWorks()
323
    {
324
        $metadata = $this->generateBookEntityFixture(['isbn' => $this->generateIsbnEmbeddableFixture()]);
325
326
        $metadata->mapField(['fieldName' => 'test', 'type' => 'string']);
327
328
        $testEmbeddableMetadata = $this->generateTestEmbeddableFixture();
329
        $this->mapEmbedded('testEmbedded', $metadata, $testEmbeddableMetadata);
330
331
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
332
333
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
334
335
        $book = $this->newInstance($metadata);
336
        $reflClass = new \ReflectionClass($metadata->name);
337
338
        $this->assertTrue($reflClass->hasProperty('name'), "Regenerating keeps property 'name'.");
339
        $this->assertTrue($reflClass->hasProperty('status'), "Regenerating keeps property 'status'.");
340
        $this->assertTrue($reflClass->hasProperty('id'), "Regenerating keeps property 'id'.");
341
        $this->assertTrue($reflClass->hasProperty('isbn'), "Regenerating keeps property 'isbn'.");
342
343
        $this->assertTrue($reflClass->hasProperty('test'), "Check for property test failed.");
344
        $this->assertTrue($reflClass->getProperty('test')->isProtected(), "Check for protected property test failed.");
345
        $this->assertTrue($reflClass->hasProperty('testEmbedded'), "Check for property testEmbedded failed.");
346
        $this->assertTrue($reflClass->getProperty('testEmbedded')->isProtected(), "Check for protected property testEmbedded failed.");
347
        $this->assertTrue($reflClass->hasMethod('getTest'), "Check for method 'getTest' failed.");
348
        $this->assertTrue($reflClass->getMethod('getTest')->isPublic(), "Check for public visibility of method 'getTest' failed.");
349
        $this->assertTrue($reflClass->hasMethod('setTest'), "Check for method 'setTest' failed.");
350
        $this->assertTrue($reflClass->getMethod('setTest')->isPublic(), "Check for public visibility of method 'setTest' failed.");
351
        $this->assertTrue($reflClass->hasMethod('getTestEmbedded'), "Check for method 'getTestEmbedded' failed.");
352
        $this->assertTrue(
353
            $reflClass->getMethod('getTestEmbedded')->isPublic(),
354
            "Check for public visibility of method 'getTestEmbedded' failed."
355
        );
356
        $this->assertTrue($reflClass->hasMethod('setTestEmbedded'), "Check for method 'setTestEmbedded' failed.");
357
        $this->assertTrue(
358
            $reflClass->getMethod('setTestEmbedded')->isPublic(),
359
            "Check for public visibility of method 'setTestEmbedded' failed."
360
        );
361
    }
362
363
    /**
364
     * @group DDC-3152
365
     */
366
    public function testDoesNotRegenerateExistingMethodsWithDifferentCase()
367
    {
368
        $metadata = $this->generateBookEntityFixture(['isbn' => $this->generateIsbnEmbeddableFixture()]);
369
370
        // Workaround to change existing fields case (just to simulate the use case)
371
        $metadata->fieldMappings['status']['fieldName'] = 'STATUS';
372
        $metadata->embeddedClasses['ISBN'] = $metadata->embeddedClasses['isbn'];
373
        unset($metadata->embeddedClasses['isbn']);
374
375
        // Should not throw a PHP fatal error
376
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
377
378
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
379
380
        $this->newInstance($metadata);
381
        $reflClass = new \ReflectionClass($metadata->name);
382
383
        $this->assertTrue($reflClass->hasProperty('status'));
384
        $this->assertTrue($reflClass->hasProperty('STATUS'));
385
        $this->assertTrue($reflClass->hasProperty('isbn'));
386
        $this->assertTrue($reflClass->hasProperty('ISBN'));
387
        $this->assertTrue($reflClass->hasMethod('getStatus'));
388
        $this->assertTrue($reflClass->hasMethod('setStatus'));
389
        $this->assertTrue($reflClass->hasMethod('getIsbn'));
390
        $this->assertTrue($reflClass->hasMethod('setIsbn'));
391
    }
392
393
    /**
394
     * @group DDC-2121
395
     */
396
    public function testMethodDocBlockShouldStartWithBackSlash()
397
    {
398
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
399
        $metadata = $this->generateBookEntityFixture(['isbn' => $embeddedMetadata]);
400
        $book     = $this->newInstance($metadata);
401
402
        $this->assertPhpDocVarType('\Doctrine\Common\Collections\Collection', new \ReflectionProperty($book, 'comments'));
403
        $this->assertPhpDocReturnType('\Doctrine\Common\Collections\Collection', new \ReflectionMethod($book, 'getComments'));
404
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorComment', new \ReflectionMethod($book, 'addComment'));
405
        $this->assertPhpDocReturnType('EntityGeneratorBook', new \ReflectionMethod($book, 'addComment'));
406
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorComment', new \ReflectionMethod($book, 'removeComment'));
407
        $this->assertPhpDocReturnType('boolean', new \ReflectionMethod($book, 'removeComment'));
408
409
        $this->assertPhpDocVarType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', new \ReflectionProperty($book, 'author'));
410
        $this->assertPhpDocReturnType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor|null', new \ReflectionMethod($book, 'getAuthor'));
411
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor|null', new \ReflectionMethod($book, 'setAuthor'));
412
413
        $expectedClassName = '\\' . $embeddedMetadata->name;
414
        $this->assertPhpDocVarType($expectedClassName, new \ReflectionProperty($book, 'isbn'));
415
        $this->assertPhpDocReturnType($expectedClassName, new \ReflectionMethod($book, 'getIsbn'));
416
        $this->assertPhpDocParamType($expectedClassName, new \ReflectionMethod($book, 'setIsbn'));
417
    }
418
419
    public function testEntityExtendsStdClass()
420
    {
421
        $this->_generator->setClassToExtend('stdClass');
422
        $metadata = $this->generateBookEntityFixture();
423
424
        $book = $this->newInstance($metadata);
425
        $this->assertInstanceOf('stdClass', $book);
426
427
        $metadata = $this->generateIsbnEmbeddableFixture();
428
        $isbn = $this->newInstance($metadata);
429
        $this->assertInstanceOf('stdClass', $isbn);
430
    }
431
432
    public function testLifecycleCallbacks()
433
    {
434
        $metadata = $this->generateBookEntityFixture();
435
436
        $book = $this->newInstance($metadata);
437
        $reflClass = new \ReflectionClass($metadata->name);
438
439
        $this->assertTrue($reflClass->hasMethod('loading'), "Check for postLoad lifecycle callback.");
440
        $this->assertTrue($reflClass->hasMethod('willBeRemoved'), "Check for preRemove lifecycle callback.");
441
    }
442
443
    public function testLoadMetadata()
444
    {
445
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
446
        $metadata = $this->generateBookEntityFixture(['isbn' => $embeddedMetadata]);
447
448
        $book = $this->newInstance($metadata);
449
450
        $reflectionService = new RuntimeReflectionService();
451
452
        $cm = new ClassMetadataInfo($metadata->name);
453
        $cm->initializeReflection($reflectionService);
454
455
        $driver = $this->createAnnotationDriver();
456
        $driver->loadMetadataForClass($cm->name, $cm);
457
458
        $this->assertEquals($cm->columnNames, $metadata->columnNames);
459
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
460
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
461
        $this->assertEquals($cm->identifier, $metadata->identifier);
462
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
463
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
464
        $this->assertEquals($cm->embeddedClasses, $metadata->embeddedClasses);
465
        $this->assertEquals($cm->isEmbeddedClass, $metadata->isEmbeddedClass);
466
467
        $this->assertEquals(ClassMetadataInfo::FETCH_EXTRA_LAZY, $cm->associationMappings['comments']['fetch']);
468
469
        $isbn = $this->newInstance($embeddedMetadata);
470
471
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
472
        $cm->initializeReflection($reflectionService);
473
474
        $driver->loadMetadataForClass($cm->name, $cm);
475
476
        $this->assertEquals($cm->columnNames, $embeddedMetadata->columnNames);
477
        $this->assertEquals($cm->embeddedClasses, $embeddedMetadata->embeddedClasses);
478
        $this->assertEquals($cm->isEmbeddedClass, $embeddedMetadata->isEmbeddedClass);
479
    }
480
481
    public function testLoadPrefixedMetadata()
482
    {
483
        $this->_generator->setAnnotationPrefix('ORM\\');
484
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
485
        $metadata = $this->generateBookEntityFixture(['isbn' => $embeddedMetadata]);
486
487
        $reader = new AnnotationReader();
488
        $driver = new AnnotationDriver($reader, []);
489
490
        $book = $this->newInstance($metadata);
491
492
        $reflectionService = new RuntimeReflectionService();
493
494
        $cm = new ClassMetadataInfo($metadata->name);
495
        $cm->initializeReflection($reflectionService);
496
497
        $driver->loadMetadataForClass($cm->name, $cm);
498
499
        $this->assertEquals($cm->columnNames, $metadata->columnNames);
500
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
501
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
502
        $this->assertEquals($cm->identifier, $metadata->identifier);
503
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
504
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
505
506
        $isbn = $this->newInstance($embeddedMetadata);
507
508
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
509
        $cm->initializeReflection($reflectionService);
510
511
        $driver->loadMetadataForClass($cm->name, $cm);
512
513
        $this->assertEquals($cm->columnNames, $embeddedMetadata->columnNames);
514
        $this->assertEquals($cm->embeddedClasses, $embeddedMetadata->embeddedClasses);
515
        $this->assertEquals($cm->isEmbeddedClass, $embeddedMetadata->isEmbeddedClass);
516
    }
517
518
    /**
519
     * @group DDC-3272
520
     */
521
    public function testMappedSuperclassAnnotationGeneration()
522
    {
523
        $metadata                     = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorBook');
524
        $metadata->namespace          = $this->_namespace;
525
        $metadata->isMappedSuperclass = true;
526
527
        $this->_generator->setAnnotationPrefix('ORM\\');
528
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
529
        $this->newInstance($metadata); // force instantiation (causes autoloading to kick in)
530
531
        $driver = new AnnotationDriver(new AnnotationReader(), []);
532
        $cm     = new ClassMetadataInfo($metadata->name);
533
534
        $cm->initializeReflection(new RuntimeReflectionService);
535
        $driver->loadMetadataForClass($cm->name, $cm);
536
537
        $this->assertTrue($cm->isMappedSuperclass);
538
    }
539
540
    /**
541
     * @dataProvider getParseTokensInEntityFileData
542
     */
543
    public function testParseTokensInEntityFile($php, $classes)
544
    {
545
        $r = new \ReflectionObject($this->_generator);
546
        $m = $r->getMethod('parseTokensInEntityFile');
547
        $m->setAccessible(true);
548
549
        $p = $r->getProperty('staticReflection');
550
        $p->setAccessible(true);
551
552
        $ret = $m->invoke($this->_generator, $php);
553
        $this->assertEquals($classes, array_keys($p->getValue($this->_generator)));
554
    }
555
556
    /**
557
     * @group DDC-1784
558
     */
559
    public function testGenerateEntityWithSequenceGenerator()
560
    {
561
        $metadata               = new ClassMetadataInfo($this->_namespace . '\DDC1784Entity');
562
        $metadata->namespace    = $this->_namespace;
563
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
564
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
565
        $metadata->setSequenceGeneratorDefinition(
566
            [
567
            'sequenceName'      => 'DDC1784_ID_SEQ',
568
            'allocationSize'    => 1,
569
            'initialValue'      => 2
570
            ]
571
        );
572
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
573
574
        $filename = $this->_tmpDir . DIRECTORY_SEPARATOR
575
                  . $this->_namespace . DIRECTORY_SEPARATOR . 'DDC1784Entity.php';
576
577
        $this->assertFileExists($filename);
578
        require_once $filename;
579
580
581
        $reflection = new \ReflectionProperty($metadata->name, 'id');
582
        $docComment = $reflection->getDocComment();
583
584
        $this->assertContains('@Id', $docComment);
585
        $this->assertContains('@Column(name="id", type="integer")', $docComment);
586
        $this->assertContains('@GeneratedValue(strategy="SEQUENCE")', $docComment);
587
        $this->assertContains('@SequenceGenerator(sequenceName="DDC1784_ID_SEQ", allocationSize=1, initialValue=2)', $docComment);
588
    }
589
590
    /**
591
     * @group DDC-2079
592
     */
593
    public function testGenerateEntityWithMultipleInverseJoinColumns()
594
    {
595
        $metadata               = new ClassMetadataInfo($this->_namespace . '\DDC2079Entity');
596
        $metadata->namespace    = $this->_namespace;
597
        $metadata->mapField(['fieldName' => 'id', 'type' => 'integer', 'id' => true]);
598
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
599
        $metadata->mapManyToMany(
600
            [
601
            'fieldName'     => 'centroCustos',
602
            'targetEntity'  => 'DDC2079CentroCusto',
603
            'joinTable'     => [
604
                'name'                  => 'unidade_centro_custo',
605
                'joinColumns'           => [
606
                    ['name' => 'idorcamento',      'referencedColumnName' => 'idorcamento'],
607
                    ['name' => 'idunidade',        'referencedColumnName' => 'idunidade']
608
                ],
609
                'inverseJoinColumns'    => [
610
                    ['name' => 'idcentrocusto',    'referencedColumnName' => 'idcentrocusto'],
611
                    ['name' => 'idpais',           'referencedColumnName' => 'idpais'],
612
                ],
613
            ],
614
            ]
615
        );
616
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
617
618
        $filename = $this->_tmpDir . DIRECTORY_SEPARATOR
619
            . $this->_namespace . DIRECTORY_SEPARATOR . 'DDC2079Entity.php';
620
621
        $this->assertFileExists($filename);
622
        require_once $filename;
623
624
        $property   = new \ReflectionProperty($metadata->name, 'centroCustos');
625
        $docComment = $property->getDocComment();
626
627
        //joinColumns
628
        $this->assertContains('@JoinColumn(name="idorcamento", referencedColumnName="idorcamento"),', $docComment);
629
        $this->assertContains('@JoinColumn(name="idunidade", referencedColumnName="idunidade")', $docComment);
630
        //inverseJoinColumns
631
        $this->assertContains('@JoinColumn(name="idcentrocusto", referencedColumnName="idcentrocusto"),', $docComment);
632
        $this->assertContains('@JoinColumn(name="idpais", referencedColumnName="idpais")', $docComment);
633
634
    }
635
636
     /**
637
     * @group DDC-2172
638
     */
639 View Code Duplication
    public function testGetInheritanceTypeString()
640
    {
641
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadataInfo');
642
        $method     = new \ReflectionMethod($this->_generator, 'getInheritanceTypeString');
643
        $constants  = $reflection->getConstants();
644
        $pattern    = '/^INHERITANCE_TYPE_/';
645
646
        $method->setAccessible(true);
647
648
        foreach ($constants as $name => $value) {
649
            if( ! preg_match($pattern, $name)) {
650
                continue;
651
            }
652
653
            $expected = preg_replace($pattern, '', $name);
654
            $actual   = $method->invoke($this->_generator, $value);
655
656
            $this->assertEquals($expected, $actual);
657
        }
658
659
        $this->expectException(\InvalidArgumentException::class);
660
        $this->expectExceptionMessage('Invalid provided InheritanceType: INVALID');
661
662
        $method->invoke($this->_generator, 'INVALID');
663
    }
664
665
    /**
666
    * @group DDC-2172
667
    */
668 View Code Duplication
    public function testGetChangeTrackingPolicyString()
669
    {
670
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadata');
671
        $method     = new \ReflectionMethod($this->_generator, 'getChangeTrackingPolicyString');
672
        $constants  = $reflection->getConstants();
673
        $pattern    = '/^CHANGETRACKING_/';
674
675
        $method->setAccessible(true);
676
677
        foreach ($constants as $name => $value) {
678
            if( ! preg_match($pattern, $name)) {
679
                continue;
680
            }
681
682
            $expected = preg_replace($pattern, '', $name);
683
            $actual   = $method->invoke($this->_generator, $value);
684
685
            $this->assertEquals($expected, $actual);
686
        }
687
688
        $this->expectException(\InvalidArgumentException::class);
689
        $this->expectExceptionMessage('Invalid provided ChangeTrackingPolicy: INVALID');
690
691
        $method->invoke($this->_generator, 'INVALID');
692
    }
693
694
    /**
695
     * @group DDC-2172
696
     */
697 View Code Duplication
    public function testGetIdGeneratorTypeString()
698
    {
699
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadataInfo');
700
        $method     = new \ReflectionMethod($this->_generator, 'getIdGeneratorTypeString');
701
        $constants  = $reflection->getConstants();
702
        $pattern    = '/^GENERATOR_TYPE_/';
703
704
        $method->setAccessible(true);
705
706
        foreach ($constants as $name => $value) {
707
            if( ! preg_match($pattern, $name)) {
708
                continue;
709
            }
710
711
            $expected = preg_replace($pattern, '', $name);
712
            $actual   = $method->invoke($this->_generator, $value);
713
714
            $this->assertEquals($expected, $actual);
715
        }
716
717
        $this->expectException(\InvalidArgumentException::class);
718
        $this->expectExceptionMessage('Invalid provided IdGeneratorType: INVALID');
719
720
        $method->invoke($this->_generator, 'INVALID');
721
    }
722
723
    /**
724
     * @dataProvider getEntityTypeAliasDataProvider
725
     *
726
     * @group DDC-1694
727
     */
728
    public function testEntityTypeAlias(array $field)
729
    {
730
        $metadata   = $this->generateEntityTypeFixture($field);
731
        $path       = $this->_tmpDir . '/'. $this->_namespace . '/EntityType.php';
732
733
        $this->assertFileExists($path);
734
        require_once $path;
735
736
        $entity     = new $metadata->name;
737
        $reflClass  = new \ReflectionClass($metadata->name);
738
739
        $type   = $field['phpType'];
740
        $name   = $field['fieldName'];
741
        $value  = $field['value'];
742
        $getter = "get" . ucfirst($name);
743
        $setter = "set" . ucfirst($name);
744
745
        $this->assertPhpDocVarType($type, $reflClass->getProperty($name));
746
        $this->assertPhpDocParamType($type, $reflClass->getMethod($setter));
747
        $this->assertPhpDocReturnType($type, $reflClass->getMethod($getter));
748
749
        $this->assertSame($entity, $entity->{$setter}($value));
750
        $this->assertEquals($value, $entity->{$getter}());
751
    }
752
753
    /**
754
     * @group DDC-2372
755
     */
756 View Code Duplication
    public function testTraitPropertiesAndMethodsAreNotDuplicated()
757
    {
758
        $cmf = new ClassMetadataFactory();
759
        $em = $this->_getTestEntityManager();
760
        $cmf->setEntityManager($em);
761
762
        $user = new DDC2372User();
763
        $metadata = $cmf->getMetadataFor(get_class($user));
764
        $metadata->name = $this->_namespace . "\DDC2372User";
0 ignored issues
show
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
765
        $metadata->namespace = $this->_namespace;
0 ignored issues
show
Accessing namespace on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
766
767
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
0 ignored issues
show
$metadata of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadataInfo>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
768
769
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/DDC2372User.php");
770
        require $this->_tmpDir . "/" . $this->_namespace . "/DDC2372User.php";
771
772
        $reflClass = new \ReflectionClass($metadata->name);
0 ignored issues
show
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
773
774
        $this->assertSame($reflClass->hasProperty('address'), false);
775
        $this->assertSame($reflClass->hasMethod('setAddress'), false);
776
        $this->assertSame($reflClass->hasMethod('getAddress'), false);
777
    }
778
779
    /**
780
     * @group DDC-2372
781
     */
782 View Code Duplication
    public function testTraitPropertiesAndMethodsAreNotDuplicatedInChildClasses()
783
    {
784
        $cmf = new ClassMetadataFactory();
785
        $em = $this->_getTestEntityManager();
786
        $cmf->setEntityManager($em);
787
788
        $user = new DDC2372Admin();
789
        $metadata = $cmf->getMetadataFor(get_class($user));
790
        $metadata->name = $this->_namespace . "\DDC2372Admin";
0 ignored issues
show
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
791
        $metadata->namespace = $this->_namespace;
0 ignored issues
show
Accessing namespace on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
792
793
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
0 ignored issues
show
$metadata of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadataInfo>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
794
795
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/DDC2372Admin.php");
796
        require $this->_tmpDir . "/" . $this->_namespace . "/DDC2372Admin.php";
797
798
        $reflClass = new \ReflectionClass($metadata->name);
0 ignored issues
show
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
799
800
        $this->assertSame($reflClass->hasProperty('address'), false);
801
        $this->assertSame($reflClass->hasMethod('setAddress'), false);
802
        $this->assertSame($reflClass->hasMethod('getAddress'), false);
803
    }
804
805
    /**
806
     * @group DDC-1590
807
     */
808
    public function testMethodsAndPropertiesAreNotDuplicatedInChildClasses()
809
    {
810
        $cmf    = new ClassMetadataFactory();
811
        $em     = $this->_getTestEntityManager();
812
813
        $cmf->setEntityManager($em);
814
815
        $ns     = $this->_namespace;
816
        $nsdir  = $this->_tmpDir . '/' . $ns;
817
818
        $content = str_replace(
819
            'namespace Doctrine\Tests\Models\DDC1590',
820
            'namespace ' . $ns,
821
            file_get_contents(__DIR__ . '/../../Models/DDC1590/DDC1590User.php')
822
        );
823
824
        $fname = $nsdir . "/DDC1590User.php";
825
        file_put_contents($fname, $content);
826
        require $fname;
827
828
829
        $metadata = $cmf->getMetadataFor($ns . '\DDC1590User');
830
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
831
832
        // class DDC1590User extends DDC1590Entity { ... }
833
        $source = file_get_contents($fname);
834
835
        // class _DDC1590User extends DDC1590Entity { ... }
836
        $source2    = str_replace('class DDC1590User', 'class _DDC1590User', $source);
837
        $fname2     = $nsdir . "/_DDC1590User.php";
838
        file_put_contents($fname2, $source2);
839
        require $fname2;
840
841
        // class __DDC1590User { ... }
842
        $source3    = str_replace('class DDC1590User extends DDC1590Entity', 'class __DDC1590User', $source);
843
        $fname3     = $nsdir . "/__DDC1590User.php";
844
        file_put_contents($fname3, $source3);
845
        require $fname3;
846
847
848
        // class _DDC1590User extends DDC1590Entity { ... }
849
        $rc2 = new \ReflectionClass($ns.'\_DDC1590User');
850
851
        $this->assertTrue($rc2->hasProperty('name'));
852
        $this->assertTrue($rc2->hasProperty('id'));
853
        $this->assertTrue($rc2->hasProperty('created_at'));
854
855
        $this->assertTrue($rc2->hasMethod('getName'));
856
        $this->assertTrue($rc2->hasMethod('setName'));
857
        $this->assertTrue($rc2->hasMethod('getId'));
858
        $this->assertFalse($rc2->hasMethod('setId'));
859
        $this->assertTrue($rc2->hasMethod('getCreatedAt'));
860
        $this->assertTrue($rc2->hasMethod('setCreatedAt'));
861
862
863
        // class __DDC1590User { ... }
864
        $rc3 = new \ReflectionClass($ns.'\__DDC1590User');
865
866
        $this->assertTrue($rc3->hasProperty('name'));
867
        $this->assertFalse($rc3->hasProperty('id'));
868
        $this->assertFalse($rc3->hasProperty('created_at'));
869
870
        $this->assertTrue($rc3->hasMethod('getName'));
871
        $this->assertTrue($rc3->hasMethod('setName'));
872
        $this->assertFalse($rc3->hasMethod('getId'));
873
        $this->assertFalse($rc3->hasMethod('setId'));
874
        $this->assertFalse($rc3->hasMethod('getCreatedAt'));
875
        $this->assertFalse($rc3->hasMethod('setCreatedAt'));
876
    }
877
878
    /**
879
     * @group DDC-3304
880
     */
881
    public function testGeneratedMutableEmbeddablesClass()
882
    {
883
        $embeddedMetadata = $this->generateTestEmbeddableFixture();
884
        $metadata = $this->generateIsbnEmbeddableFixture(['test' => $embeddedMetadata]);
885
886
        $isbn = $this->newInstance($metadata);
887
888
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
889
        $this->assertFalse(method_exists($metadata->name, '__construct'), "EntityGeneratorIsbn::__construct present.");
890
        $this->assertTrue(method_exists($metadata->name, 'getPrefix'), "EntityGeneratorIsbn::getPrefix() missing.");
891
        $this->assertTrue(method_exists($metadata->name, 'setPrefix'), "EntityGeneratorIsbn::setPrefix() missing.");
892
        $this->assertTrue(method_exists($metadata->name, 'getGroupNumber'), "EntityGeneratorIsbn::getGroupNumber() missing.");
893
        $this->assertTrue(method_exists($metadata->name, 'setGroupNumber'), "EntityGeneratorIsbn::setGroupNumber() missing.");
894
        $this->assertTrue(method_exists($metadata->name, 'getPublisherNumber'), "EntityGeneratorIsbn::getPublisherNumber() missing.");
895
        $this->assertTrue(method_exists($metadata->name, 'setPublisherNumber'), "EntityGeneratorIsbn::setPublisherNumber() missing.");
896
        $this->assertTrue(method_exists($metadata->name, 'getTitleNumber'), "EntityGeneratorIsbn::getTitleNumber() missing.");
897
        $this->assertTrue(method_exists($metadata->name, 'setTitleNumber'), "EntityGeneratorIsbn::setTitleNumber() missing.");
898
        $this->assertTrue(method_exists($metadata->name, 'getCheckDigit'), "EntityGeneratorIsbn::getCheckDigit() missing.");
899
        $this->assertTrue(method_exists($metadata->name, 'setCheckDigit'), "EntityGeneratorIsbn::setCheckDigit() missing.");
900
        $this->assertTrue(method_exists($metadata->name, 'getTest'), "EntityGeneratorIsbn::getTest() missing.");
901
        $this->assertTrue(method_exists($metadata->name, 'setTest'), "EntityGeneratorIsbn::setTest() missing.");
902
903
        $isbn->setPrefix(978);
904
        $this->assertSame(978, $isbn->getPrefix());
905
906
        $this->newInstance($embeddedMetadata);
907
        $test = new $embeddedMetadata->name();
908
909
        $isbn->setTest($test);
910
        $this->assertSame($test, $isbn->getTest());
911
912
        $reflMethod = new \ReflectionMethod($metadata->name, 'setTest');
913
        $reflParameters = $reflMethod->getParameters();
914
        $this->assertEquals($embeddedMetadata->name, $reflParameters[0]->getClass()->name);
915
    }
916
917
    /**
918
     * @group DDC-3304
919
     */
920
    public function testGeneratedImmutableEmbeddablesClass()
921
    {
922
        $this->_generator->setEmbeddablesImmutable(true);
923
        $embeddedMetadata = $this->generateTestEmbeddableFixture();
924
        $metadata = $this->generateIsbnEmbeddableFixture(['test' => $embeddedMetadata]);
925
926
        $this->loadEntityClass($embeddedMetadata);
927
        $this->loadEntityClass($metadata);
928
929
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
930
        $this->assertTrue(method_exists($metadata->name, '__construct'), "EntityGeneratorIsbn::__construct missing.");
931
        $this->assertTrue(method_exists($metadata->name, 'getPrefix'), "EntityGeneratorIsbn::getPrefix() missing.");
932
        $this->assertFalse(method_exists($metadata->name, 'setPrefix'), "EntityGeneratorIsbn::setPrefix() present.");
933
        $this->assertTrue(method_exists($metadata->name, 'getGroupNumber'), "EntityGeneratorIsbn::getGroupNumber() missing.");
934
        $this->assertFalse(method_exists($metadata->name, 'setGroupNumber'), "EntityGeneratorIsbn::setGroupNumber() present.");
935
        $this->assertTrue(method_exists($metadata->name, 'getPublisherNumber'), "EntityGeneratorIsbn::getPublisherNumber() missing.");
936
        $this->assertFalse(method_exists($metadata->name, 'setPublisherNumber'), "EntityGeneratorIsbn::setPublisherNumber() present.");
937
        $this->assertTrue(method_exists($metadata->name, 'getTitleNumber'), "EntityGeneratorIsbn::getTitleNumber() missing.");
938
        $this->assertFalse(method_exists($metadata->name, 'setTitleNumber'), "EntityGeneratorIsbn::setTitleNumber() present.");
939
        $this->assertTrue(method_exists($metadata->name, 'getCheckDigit'), "EntityGeneratorIsbn::getCheckDigit() missing.");
940
        $this->assertFalse(method_exists($metadata->name, 'setCheckDigit'), "EntityGeneratorIsbn::setCheckDigit() present.");
941
        $this->assertTrue(method_exists($metadata->name, 'getTest'), "EntityGeneratorIsbn::getTest() missing.");
942
        $this->assertFalse(method_exists($metadata->name, 'setTest'), "EntityGeneratorIsbn::setTest() present.");
943
944
        $test = new $embeddedMetadata->name(1, new \DateTime());
945
        $isbn = new $metadata->name($test, 978, 3, 12, 732320, 83);
946
947
        $reflMethod = new \ReflectionMethod($isbn, '__construct');
948
        $reflParameters = $reflMethod->getParameters();
949
950
        $this->assertCount(6, $reflParameters);
951
952
        $this->assertSame($embeddedMetadata->name, $reflParameters[0]->getClass()->name);
953
        $this->assertSame('test', $reflParameters[0]->getName());
954
        $this->assertFalse($reflParameters[0]->isOptional());
955
956
        $this->assertSame('prefix', $reflParameters[1]->getName());
957
        $this->assertFalse($reflParameters[1]->isOptional());
958
959
        $this->assertSame('groupNumber', $reflParameters[2]->getName());
960
        $this->assertFalse($reflParameters[2]->isOptional());
961
962
        $this->assertSame('publisherNumber', $reflParameters[3]->getName());
963
        $this->assertFalse($reflParameters[3]->isOptional());
964
965
        $this->assertSame('titleNumber', $reflParameters[4]->getName());
966
        $this->assertFalse($reflParameters[4]->isOptional());
967
968
        $this->assertSame('checkDigit', $reflParameters[5]->getName());
969
        $this->assertFalse($reflParameters[5]->isOptional());
970
971
        $reflMethod = new \ReflectionMethod($test, '__construct');
972
        $reflParameters = $reflMethod->getParameters();
973
974
        $this->assertCount(4, $reflParameters);
975
976
        $this->assertSame('field1', $reflParameters[0]->getName());
977
        $this->assertFalse($reflParameters[0]->isOptional());
978
979
        $this->assertSame('DateTime', $reflParameters[1]->getClass()->name);
980
        $this->assertSame('field3', $reflParameters[1]->getName());
981
        $this->assertFalse($reflParameters[1]->isOptional());
982
983
        $this->assertSame('field2', $reflParameters[2]->getName());
984
        $this->assertTrue($reflParameters[2]->isOptional());
985
986
        $this->assertSame('DateTime', $reflParameters[3]->getClass()->name);
987
        $this->assertSame('field4', $reflParameters[3]->getName());
988
        $this->assertTrue($reflParameters[3]->isOptional());
989
    }
990
991
    public function testRegenerateEntityClass()
992
    {
993
        $metadata = $this->generateBookEntityFixture();
994
        $this->loadEntityClass($metadata);
995
996
        $className = basename(str_replace('\\', '/', $metadata->name));
997
        $path = $this->_tmpDir . '/' . $this->_namespace . '/' . $className . '.php';
998
        $classTest = file_get_contents($path);
999
1000
        $this->_generator->setRegenerateEntityIfExists(true);
1001
        $this->_generator->setBackupExisting(false);
1002
1003
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
1004
        $classNew = file_get_contents($path);
1005
1006
        $this->assertSame($classTest,$classNew);
1007
    }
1008
1009
    /**
1010
     * @return array
1011
     */
1012
    public function getEntityTypeAliasDataProvider()
1013
    {
1014
        return [
1015
            [
1016
                [
1017
                'fieldName' => 'datetimetz',
1018
                'phpType' => '\\DateTime',
1019
                'dbType' => 'datetimetz',
1020
                'value' => new \DateTime
1021
                ]
1022
            ],
1023
            [
1024
                [
1025
                'fieldName' => 'datetime',
1026
                'phpType' => '\\DateTime',
1027
                'dbType' => 'datetime',
1028
                'value' => new \DateTime
1029
                ]
1030
            ],
1031
            [
1032
                [
1033
                'fieldName' => 'date',
1034
                'phpType' => '\\DateTime',
1035
                'dbType' => 'date',
1036
                'value' => new \DateTime
1037
                ]
1038
            ],
1039
            [
1040
                [
1041
                'fieldName' => 'time',
1042
                'phpType' => '\DateTime',
1043
                'dbType' => 'time',
1044
                'value' => new \DateTime
1045
                ]
1046
            ],
1047
            [
1048
                [
1049
                'fieldName' => 'object',
1050
                'phpType' => '\stdClass',
1051
                'dbType' => 'object',
1052
                'value' => new \stdClass()
1053
                ]
1054
            ],
1055
            [
1056
                [
1057
                'fieldName' => 'bigint',
1058
                'phpType' => 'int',
1059
                'dbType' => 'bigint',
1060
                'value' => 11
1061
                ]
1062
            ],
1063
            [
1064
                [
1065
                'fieldName' => 'smallint',
1066
                'phpType' => 'int',
1067
                'dbType' => 'smallint',
1068
                'value' => 22
1069
                ]
1070
            ],
1071
            [
1072
                [
1073
                'fieldName' => 'text',
1074
                'phpType' => 'string',
1075
                'dbType' => 'text',
1076
                'value' => 'text'
1077
                ]
1078
            ],
1079
            [
1080
                [
1081
                'fieldName' => 'blob',
1082
                'phpType' => 'string',
1083
                'dbType' => 'blob',
1084
                'value' => 'blob'
1085
                ]
1086
            ],
1087
            [
1088
                [
1089
                'fieldName' => 'decimal',
1090
                'phpType' => 'string',
1091
                'dbType' => 'decimal',
1092
                'value' => '12.34'
1093
                ],
1094
            ]
1095
        ];
1096
    }
1097
1098
    public function getParseTokensInEntityFileData()
1099
    {
1100
        return [
1101
            [
1102
                '<?php namespace Foo\Bar; class Baz {}',
1103
                ['Foo\Bar\Baz'],
1104
            ],
1105
            [
1106
                '<?php namespace Foo\Bar; use Foo; class Baz {}',
1107
                ['Foo\Bar\Baz'],
1108
            ],
1109
            [
1110
                '<?php namespace /*Comment*/ Foo\Bar; /** Foo */class /* Comment */ Baz {}',
1111
                ['Foo\Bar\Baz'],
1112
            ],
1113
            [
1114
                '
1115
<?php namespace
1116
/*Comment*/
1117
Foo\Bar
1118
;
1119
1120
/** Foo */
1121
class
1122
/* Comment */
1123
 Baz {}
1124
     ',
1125
                ['Foo\Bar\Baz'],
1126
            ],
1127
            [
1128
                '
1129
<?php namespace Foo\Bar; class Baz {
1130
    public static function someMethod(){
1131
        return self::class;
1132
    }
1133
}
1134
',
1135
                ['Foo\Bar\Baz'],
1136
            ],
1137
        ];
1138
    }
1139
1140
    /**
1141
     * @param string $type
1142
     * @param \ReflectionProperty $property
1143
     */
1144 View Code Duplication
    private function assertPhpDocVarType($type, \ReflectionProperty $property)
1145
    {
1146
        $docComment = $property->getDocComment();
1147
        $regex      = '/@var\s+([\S]+)$/m';
1148
1149
        $this->assertRegExp($regex, $docComment);
1150
        $this->assertEquals(1, preg_match($regex, $docComment, $matches));
1151
        $this->assertEquals($type, $matches[1]);
1152
    }
1153
1154
    /**
1155
     * @param string $type
1156
     * @param \ReflectionMethod $method
1157
     */
1158 View Code Duplication
    private function assertPhpDocReturnType($type, \ReflectionMethod $method)
1159
    {
1160
        $docComment = $method->getDocComment();
1161
        $regex      = '/@return\s+([\S]+)(\s+.*)$/m';
1162
1163
        $this->assertRegExp($regex, $docComment);
1164
        $this->assertEquals(1, preg_match($regex, $docComment, $matches));
1165
        $this->assertEquals($type, $matches[1]);
1166
    }
1167
1168
    /**
1169
     * @param string $type
1170
     * @param \ReflectionProperty $method
1171
     */
1172
    private function assertPhpDocParamType($type, \ReflectionMethod $method)
1173
    {
1174
        $this->assertEquals(1, preg_match('/@param\s+([^\s]+)/', $method->getDocComment(), $matches));
1175
        $this->assertEquals($type, $matches[1]);
1176
    }
1177
}
1178
1179
class EntityGeneratorAuthor {}
1180
class EntityGeneratorComment {}
1181