Completed
Pull Request — master (#5569)
by Jérémy
10:47
created

EntityGeneratorTest::newInstance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace Doctrine\Tests\ORM\Tools;
4
5
use Doctrine\Common\Annotations\AnnotationReader;
6
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
7
use Doctrine\ORM\Mapping\ClassMetadataFactory;
8
use Doctrine\ORM\Mapping\ClassMetadataInfo;
9
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
10
use Doctrine\ORM\Tools\EntityGenerator;
11
use Doctrine\Tests\Models\DDC2372\DDC2372Admin;
12
use Doctrine\Tests\Models\DDC2372\DDC2372User;
13
use Doctrine\Tests\OrmTestCase;
14
15
class EntityGeneratorTest extends OrmTestCase
16
{
17
18
    /**
19
     * @var EntityGenerator
20
     */
21
    private $_generator;
22
    private $_tmpDir;
23
    private $_namespace;
24
25
    public function setUp()
26
    {
27
        $this->_namespace = uniqid("doctrine_");
28
        $this->_tmpDir = \sys_get_temp_dir();
29
        \mkdir($this->_tmpDir . \DIRECTORY_SEPARATOR . $this->_namespace);
30
        $this->_generator = new EntityGenerator();
31
        $this->_generator->setAnnotationPrefix("");
32
        $this->_generator->setGenerateAnnotations(true);
33
        $this->_generator->setGenerateStubMethods(true);
34
        $this->_generator->setRegenerateEntityIfExists(false);
35
        $this->_generator->setStrictTypes(false);
36
        $this->_generator->setGenerateMethodsTypeHinting(false);
37
        $this->_generator->setUpdateEntityIfExists(true);
38
        $this->_generator->setFieldVisibility(EntityGenerator::FIELD_VISIBLE_PROTECTED);
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 = array())
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'] = array('columns' => array('name'));
66
        $metadata->table['indexes']['status_idx'] = array('columns' => array('status'));
67
        $metadata->mapField(array('fieldName' => 'name', 'type' => 'string'));
68
        $metadata->mapField(array('fieldName' => 'status', 'type' => 'string', 'options' => array('default' => 'published')));
69
        $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
70
        $metadata->mapOneToOne(array('fieldName' => 'author', 'targetEntity' => 'Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', 'mappedBy' => 'book'));
71
        $joinColumns = array(
0 ignored issues
show
Unused Code introduced by
$joinColumns is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
72
            array('name' => 'author_id', 'referencedColumnName' => 'id')
73
        );
74
        $metadata->mapManyToMany(array(
75
            'fieldName' => 'comments',
76
            'targetEntity' => 'Doctrine\Tests\ORM\Tools\EntityGeneratorComment',
77
            'fetch' => ClassMetadataInfo::FETCH_EXTRA_LAZY,
78
            'joinTable' => array(
79
                'name' => 'book_comment',
80
                'joinColumns' => array(array('name' => 'book_id', 'referencedColumnName' => 'id')),
81
                'inverseJoinColumns' => array(array('name' => 'comment_id', 'referencedColumnName' => 'id')),
82
            ),
83
        ));
84
        $metadata->addLifecycleCallback('loading', 'postLoad');
85
        $metadata->addLifecycleCallback('willBeRemoved', 'preRemove');
86
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
87
88
        foreach ($embeddedClasses as $fieldName => $embeddedClass) {
89
            $this->mapNestedEmbedded($fieldName, $metadata, $embeddedClass);
90
            $this->mapEmbedded($fieldName, $metadata, $embeddedClass);
91
        }
92
93
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
94
95
        return $metadata;
96
    }
97
98
    private function generateEntityTypeFixture(array $field)
99
    {
100
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityType');
101
        $metadata->namespace = $this->_namespace;
102
103
        $metadata->table['name'] = 'entity_type';
104
        $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
105
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
106
107
        $name  = $field['fieldName'];
108
        $type  = $field['dbType'];
109
        $metadata->mapField(array('fieldName' => $name, 'type' => $type));
110
111
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
112
113
        return $metadata;
114
    }
115
116
    /**
117
     * @return ClassMetadataInfo
118
     */
119
    private function generateIsbnEmbeddableFixture(array $embeddedClasses = array())
120
    {
121
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorIsbn');
122
        $metadata->namespace = $this->_namespace;
123
        $metadata->isEmbeddedClass = true;
124
        $metadata->mapField(array('fieldName' => 'prefix', 'type' => 'integer'));
125
        $metadata->mapField(array('fieldName' => 'groupNumber', 'type' => 'integer'));
126
        $metadata->mapField(array('fieldName' => 'publisherNumber', 'type' => 'integer'));
127
        $metadata->mapField(array('fieldName' => 'titleNumber', 'type' => 'integer'));
128
        $metadata->mapField(array('fieldName' => 'checkDigit', 'type' => 'integer'));
129
130
        foreach ($embeddedClasses as $fieldName => $embeddedClass) {
131
            $this->mapEmbedded($fieldName, $metadata, $embeddedClass);
132
        }
133
134
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
135
136
        return $metadata;
137
    }
138
139
    /**
140
     * @return ClassMetadataInfo
141
     */
142
    private function generateTestEmbeddableFixture()
143
    {
144
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorTestEmbeddable');
145
        $metadata->namespace = $this->_namespace;
146
        $metadata->isEmbeddedClass = true;
147
        $metadata->mapField(array('fieldName' => 'field1', 'type' => 'integer'));
148
        $metadata->mapField(array('fieldName' => 'field2', 'type' => 'integer', 'nullable' => true));
149
        $metadata->mapField(array('fieldName' => 'field3', 'type' => 'datetime'));
150
        $metadata->mapField(array('fieldName' => 'field4', 'type' => 'datetime', 'nullable' => true));
151
152
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
153
154
        return $metadata;
155
    }
156
157
    /**
158
     * @param string            $fieldName
159
     * @param ClassMetadataInfo $classMetadata
160
     * @param ClassMetadataInfo $embeddableMetadata
161
     * @param string|null       $columnPrefix
162
     */
163
    private function mapEmbedded(
164
        $fieldName,
165
        ClassMetadataInfo $classMetadata,
166
        ClassMetadataInfo $embeddableMetadata,
167
        $columnPrefix = false
168
    ) {
169
        $classMetadata->mapEmbedded(
170
            array('fieldName' => $fieldName, 'class' => $embeddableMetadata->name, 'columnPrefix' => $columnPrefix)
171
        );
172
    }
173
174
    /**
175
     * @param string            $fieldName
176
     * @param ClassMetadataInfo $classMetadata
177
     * @param ClassMetadataInfo $embeddableMetadata
178
     */
179
    private function mapNestedEmbedded(
180
        $fieldName,
181
        ClassMetadataInfo $classMetadata,
182
        ClassMetadataInfo $embeddableMetadata
183
    ) {
184
        foreach ($embeddableMetadata->embeddedClasses as $property => $embeddableClass) {
185
            $classMetadata->mapEmbedded(array(
186
                'fieldName' => $fieldName . '.' . $property,
187
                'class' => $embeddableClass['class'],
188
                'columnPrefix' => $embeddableClass['columnPrefix'],
189
                'declaredField' => $embeddableClass['declaredField']
190
                        ? $fieldName . '.' . $embeddableClass['declaredField']
191
                        : $fieldName,
192
                'originalField' => $embeddableClass['originalField'] ?: $property,
193
            ));
194
        }
195
    }
196
197
    /**
198
     * @param ClassMetadataInfo $metadata
199
     */
200
    private function loadEntityClass(ClassMetadataInfo $metadata)
201
    {
202
        $className = basename(str_replace('\\', '/', $metadata->name));
203
        $path = $this->_tmpDir . '/' . $this->_namespace . '/' . $className . '.php';
204
205
        $this->assertFileExists($path);
206
207
        require_once $path;
208
    }
209
210
    /**
211
     * @param  ClassMetadataInfo $metadata
212
     *
213
     * @return mixed An instance of the given metadata's class.
214
     */
215
    public function newInstance($metadata)
216
    {
217
        $this->loadEntityClass($metadata);
218
219
        return new $metadata->name;
220
    }
221
222
    public function testGeneratedEntityClass()
223
    {
224
        $testMetadata = $this->generateTestEmbeddableFixture();
225
        $isbnMetadata = $this->generateIsbnEmbeddableFixture(array('test' => $testMetadata));
226
        $metadata = $this->generateBookEntityFixture(array('isbn' => $isbnMetadata));
227
228
        $book = $this->newInstance($metadata);
229
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
230
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', '__construct'), "EntityGeneratorBook::__construct() missing.");
231
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getId'), "EntityGeneratorBook::getId() missing.");
232
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setName'), "EntityGeneratorBook::setName() missing.");
233
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getName'), "EntityGeneratorBook::getName() missing.");
234
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setStatus'), "EntityGeneratorBook::setStatus() missing.");
235
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getStatus'), "EntityGeneratorBook::getStatus() missing.");
236
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setAuthor'), "EntityGeneratorBook::setAuthor() missing.");
237
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getAuthor'), "EntityGeneratorBook::getAuthor() missing.");
238
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getComments'), "EntityGeneratorBook::getComments() missing.");
239
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'addComment'), "EntityGeneratorBook::addComment() missing.");
240
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'removeComment'), "EntityGeneratorBook::removeComment() missing.");
241
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setIsbn'), "EntityGeneratorBook::setIsbn() missing.");
242
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getIsbn'), "EntityGeneratorBook::getIsbn() missing.");
243
244
        $reflClass = new \ReflectionClass($metadata->name);
245
246
        $this->assertCount(6, $reflClass->getProperties());
247
        $this->assertCount(15, $reflClass->getMethods());
248
249
        $this->assertEquals('published', $book->getStatus());
250
251
        $book->setName('Jonathan H. Wage');
252
        $this->assertEquals('Jonathan H. Wage', $book->getName());
253
254
        $reflMethod = new \ReflectionMethod($metadata->name, 'addComment');
255
        $addCommentParameters = $reflMethod->getParameters();
256
        $this->assertEquals('comment', $addCommentParameters[0]->getName());
257
258
        $reflMethod = new \ReflectionMethod($metadata->name, 'removeComment');
259
        $removeCommentParameters = $reflMethod->getParameters();
260
        $this->assertEquals('comment', $removeCommentParameters[0]->getName());
261
262
        $author = new EntityGeneratorAuthor();
263
        $book->setAuthor($author);
264
        $this->assertEquals($author, $book->getAuthor());
265
266
        $comment = new EntityGeneratorComment();
267
        $this->assertInstanceOf($metadata->name, $book->addComment($comment));
268
        $this->assertInstanceOf('Doctrine\Common\Collections\ArrayCollection', $book->getComments());
269
        $this->assertEquals(new \Doctrine\Common\Collections\ArrayCollection(array($comment)), $book->getComments());
270
        $this->assertInternalType('boolean', $book->removeComment($comment));
271
        $this->assertEquals(new \Doctrine\Common\Collections\ArrayCollection(array()), $book->getComments());
272
273
        $this->newInstance($isbnMetadata);
274
        $isbn = new $isbnMetadata->name();
275
276
        $book->setIsbn($isbn);
277
        $this->assertSame($isbn, $book->getIsbn());
278
279
        $reflMethod = new \ReflectionMethod($metadata->name, 'setIsbn');
280
        $reflParameters = $reflMethod->getParameters();
281
        $this->assertEquals($isbnMetadata->name, $reflParameters[0]->getClass()->name);
282
    }
283
284
    public function testEntityUpdatingWorks()
285
    {
286
        $metadata = $this->generateBookEntityFixture(array('isbn' => $this->generateIsbnEmbeddableFixture()));
287
288
        $metadata->mapField(array('fieldName' => 'test', 'type' => 'string'));
289
290
        $testEmbeddableMetadata = $this->generateTestEmbeddableFixture();
291
        $this->mapEmbedded('testEmbedded', $metadata, $testEmbeddableMetadata);
292
293
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
294
295
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
296
297
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
$book is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
298
        $reflClass = new \ReflectionClass($metadata->name);
299
300
        $this->assertTrue($reflClass->hasProperty('name'), "Regenerating keeps property 'name'.");
301
        $this->assertTrue($reflClass->hasProperty('status'), "Regenerating keeps property 'status'.");
302
        $this->assertTrue($reflClass->hasProperty('id'), "Regenerating keeps property 'id'.");
303
        $this->assertTrue($reflClass->hasProperty('isbn'), "Regenerating keeps property 'isbn'.");
304
305
        $this->assertTrue($reflClass->hasProperty('test'), "Check for property test failed.");
306
        $this->assertTrue($reflClass->getProperty('test')->isProtected(), "Check for protected property test failed.");
307
        $this->assertTrue($reflClass->hasProperty('testEmbedded'), "Check for property testEmbedded failed.");
308
        $this->assertTrue($reflClass->getProperty('testEmbedded')->isProtected(), "Check for protected property testEmbedded failed.");
309
        $this->assertTrue($reflClass->hasMethod('getTest'), "Check for method 'getTest' failed.");
310
        $this->assertTrue($reflClass->getMethod('getTest')->isPublic(), "Check for public visibility of method 'getTest' failed.");
311
        $this->assertTrue($reflClass->hasMethod('setTest'), "Check for method 'setTest' failed.");
312
        $this->assertTrue($reflClass->getMethod('setTest')->isPublic(), "Check for public visibility of method 'setTest' failed.");
313
        $this->assertTrue($reflClass->hasMethod('getTestEmbedded'), "Check for method 'getTestEmbedded' failed.");
314
        $this->assertTrue(
315
            $reflClass->getMethod('getTestEmbedded')->isPublic(),
316
            "Check for public visibility of method 'getTestEmbedded' failed."
317
        );
318
        $this->assertTrue($reflClass->hasMethod('setTestEmbedded'), "Check for method 'setTestEmbedded' failed.");
319
        $this->assertTrue(
320
            $reflClass->getMethod('setTestEmbedded')->isPublic(),
321
            "Check for public visibility of method 'setTestEmbedded' failed."
322
        );
323
    }
324
325
    /**
326
     * @group DDC-3152
327
     */
328
    public function testDoesNotRegenerateExistingMethodsWithDifferentCase()
329
    {
330
        $metadata = $this->generateBookEntityFixture(array('isbn' => $this->generateIsbnEmbeddableFixture()));
331
332
        // Workaround to change existing fields case (just to simulate the use case)
333
        $metadata->fieldMappings['status']['fieldName'] = 'STATUS';
334
        $metadata->embeddedClasses['ISBN'] = $metadata->embeddedClasses['isbn'];
335
        unset($metadata->embeddedClasses['isbn']);
336
337
        // Should not throw a PHP fatal error
338
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
339
340
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
341
342
        $this->newInstance($metadata);
343
        $reflClass = new \ReflectionClass($metadata->name);
344
345
        $this->assertTrue($reflClass->hasProperty('status'));
346
        $this->assertTrue($reflClass->hasProperty('STATUS'));
347
        $this->assertTrue($reflClass->hasProperty('isbn'));
348
        $this->assertTrue($reflClass->hasProperty('ISBN'));
349
        $this->assertTrue($reflClass->hasMethod('getStatus'));
350
        $this->assertTrue($reflClass->hasMethod('setStatus'));
351
        $this->assertTrue($reflClass->hasMethod('getIsbn'));
352
        $this->assertTrue($reflClass->hasMethod('setIsbn'));
353
    }
354
355
    /**
356
     * @group DDC-2121
357
     */
358
    public function testMethodDocBlockShouldStartWithBackSlash()
359
    {
360
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
361
        $metadata = $this->generateBookEntityFixture(array('isbn' => $embeddedMetadata));
362
        $book     = $this->newInstance($metadata);
363
364
        $this->assertPhpDocVarType('\Doctrine\Common\Collections\Collection', new \ReflectionProperty($book, 'comments'));
365
        $this->assertPhpDocReturnType('\Doctrine\Common\Collections\Collection', new \ReflectionMethod($book, 'getComments'));
366
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorComment', new \ReflectionMethod($book, 'addComment'));
367
        $this->assertPhpDocReturnType('EntityGeneratorBook', new \ReflectionMethod($book, 'addComment'));
368
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorComment', new \ReflectionMethod($book, 'removeComment'));
369
        $this->assertPhpDocReturnType('boolean', new \ReflectionMethod($book, 'removeComment'));
370
371
        $this->assertPhpDocVarType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', new \ReflectionProperty($book, 'author'));
372
        $this->assertPhpDocReturnType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', new \ReflectionMethod($book, 'getAuthor'));
373
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', new \ReflectionMethod($book, 'setAuthor'));
374
375
        $expectedClassName = '\\' . $embeddedMetadata->name;
376
        $this->assertPhpDocVarType($expectedClassName, new \ReflectionProperty($book, 'isbn'));
377
        $this->assertPhpDocReturnType($expectedClassName, new \ReflectionMethod($book, 'getIsbn'));
378
        $this->assertPhpDocParamType($expectedClassName, new \ReflectionMethod($book, 'setIsbn'));
379
    }
380
381
    public function testEntityExtendsStdClass()
382
    {
383
        $this->_generator->setClassToExtend('stdClass');
384
        $metadata = $this->generateBookEntityFixture();
385
386
        $book = $this->newInstance($metadata);
387
        $this->assertInstanceOf('stdClass', $book);
388
389
        $metadata = $this->generateIsbnEmbeddableFixture();
390
        $isbn = $this->newInstance($metadata);
391
        $this->assertInstanceOf('stdClass', $isbn);
392
    }
393
394
    public function testLifecycleCallbacks()
395
    {
396
        $metadata = $this->generateBookEntityFixture();
397
398
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
$book is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
399
        $reflClass = new \ReflectionClass($metadata->name);
400
401
        $this->assertTrue($reflClass->hasMethod('loading'), "Check for postLoad lifecycle callback.");
402
        $this->assertTrue($reflClass->hasMethod('willBeRemoved'), "Check for preRemove lifecycle callback.");
403
    }
404
405
    public function testLoadMetadata()
406
    {
407
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
408
        $metadata = $this->generateBookEntityFixture(array('isbn' => $embeddedMetadata));
409
410
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
$book is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
411
412
        $reflectionService = new RuntimeReflectionService();
413
414
        $cm = new ClassMetadataInfo($metadata->name);
415
        $cm->initializeReflection($reflectionService);
416
417
        $driver = $this->createAnnotationDriver();
418
        $driver->loadMetadataForClass($cm->name, $cm);
419
420
        $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 with message: 3.0 Remove this.

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...
421
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
422
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
423
        $this->assertEquals($cm->identifier, $metadata->identifier);
424
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
425
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
426
        $this->assertEquals($cm->embeddedClasses, $metadata->embeddedClasses);
427
        $this->assertEquals($cm->isEmbeddedClass, $metadata->isEmbeddedClass);
428
429
        $this->assertEquals(ClassMetadataInfo::FETCH_EXTRA_LAZY, $cm->associationMappings['comments']['fetch']);
430
431
        $isbn = $this->newInstance($embeddedMetadata);
0 ignored issues
show
Unused Code introduced by
$isbn is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
432
433
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
434
        $cm->initializeReflection($reflectionService);
435
436
        $driver->loadMetadataForClass($cm->name, $cm);
437
438
        $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 with message: 3.0 Remove this.

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...
439
        $this->assertEquals($cm->embeddedClasses, $embeddedMetadata->embeddedClasses);
440
        $this->assertEquals($cm->isEmbeddedClass, $embeddedMetadata->isEmbeddedClass);
441
    }
442
443
    public function testLoadPrefixedMetadata()
444
    {
445
        $this->_generator->setAnnotationPrefix('ORM\\');
446
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
447
        $metadata = $this->generateBookEntityFixture(array('isbn' => $embeddedMetadata));
448
449
        $reader = new AnnotationReader();
450
        $driver = new AnnotationDriver($reader, array());
451
452
        $book = $this->newInstance($metadata);
0 ignored issues
show
Unused Code introduced by
$book is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
453
454
        $reflectionService = new RuntimeReflectionService();
455
456
        $cm = new ClassMetadataInfo($metadata->name);
457
        $cm->initializeReflection($reflectionService);
458
459
        $driver->loadMetadataForClass($cm->name, $cm);
460
461
        $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 with message: 3.0 Remove this.

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...
462
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
463
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
464
        $this->assertEquals($cm->identifier, $metadata->identifier);
465
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
466
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
467
468
        $isbn = $this->newInstance($embeddedMetadata);
0 ignored issues
show
Unused Code introduced by
$isbn is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
469
470
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
471
        $cm->initializeReflection($reflectionService);
472
473
        $driver->loadMetadataForClass($cm->name, $cm);
474
475
        $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 with message: 3.0 Remove this.

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...
476
        $this->assertEquals($cm->embeddedClasses, $embeddedMetadata->embeddedClasses);
477
        $this->assertEquals($cm->isEmbeddedClass, $embeddedMetadata->isEmbeddedClass);
478
    }
479
480
    /**
481
     * @group DDC-3272
482
     */
483
    public function testMappedSuperclassAnnotationGeneration()
484
    {
485
        $metadata                     = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorBook');
486
        $metadata->namespace          = $this->_namespace;
487
        $metadata->isMappedSuperclass = true;
488
489
        $this->_generator->setAnnotationPrefix('ORM\\');
490
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
491
        $this->newInstance($metadata); // force instantiation (causes autoloading to kick in)
492
493
        $driver = new AnnotationDriver(new AnnotationReader(), array());
494
        $cm     = new ClassMetadataInfo($metadata->name);
495
496
        $cm->initializeReflection(new RuntimeReflectionService);
497
        $driver->loadMetadataForClass($cm->name, $cm);
498
499
        $this->assertTrue($cm->isMappedSuperclass);
500
    }
501
502
    /**
503
     * @dataProvider getParseTokensInEntityFileData
504
     */
505
    public function testParseTokensInEntityFile($php, $classes)
506
    {
507
        $r = new \ReflectionObject($this->_generator);
508
        $m = $r->getMethod('parseTokensInEntityFile');
509
        $m->setAccessible(true);
510
511
        $p = $r->getProperty('staticReflection');
512
        $p->setAccessible(true);
513
514
        $ret = $m->invoke($this->_generator, $php);
0 ignored issues
show
Unused Code introduced by
$ret is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
515
        $this->assertEquals($classes, array_keys($p->getValue($this->_generator)));
516
    }
517
518
    /**
519
     * @group DDC-1784
520
     */
521
    public function testGenerateEntityWithSequenceGenerator()
522
    {
523
        $metadata               = new ClassMetadataInfo($this->_namespace . '\DDC1784Entity');
524
        $metadata->namespace    = $this->_namespace;
525
        $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
526
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
527
        $metadata->setSequenceGeneratorDefinition(array(
528
            'sequenceName'      => 'DDC1784_ID_SEQ',
529
            'allocationSize'    => 1,
530
            'initialValue'      => 2
531
        ));
532
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
533
534
        $filename = $this->_tmpDir . DIRECTORY_SEPARATOR
535
                  . $this->_namespace . DIRECTORY_SEPARATOR . 'DDC1784Entity.php';
536
537
        $this->assertFileExists($filename);
538
        require_once $filename;
539
540
541
        $reflection = new \ReflectionProperty($metadata->name, 'id');
542
        $docComment = $reflection->getDocComment();
543
544
        $this->assertContains('@Id', $docComment);
545
        $this->assertContains('@Column(name="id", type="integer")', $docComment);
546
        $this->assertContains('@GeneratedValue(strategy="SEQUENCE")', $docComment);
547
        $this->assertContains('@SequenceGenerator(sequenceName="DDC1784_ID_SEQ", allocationSize=1, initialValue=2)', $docComment);
548
    }
549
550
    /**
551
     * @group DDC-2079
552
     */
553
    public function testGenerateEntityWithMultipleInverseJoinColumns()
554
    {
555
        $metadata               = new ClassMetadataInfo($this->_namespace . '\DDC2079Entity');
556
        $metadata->namespace    = $this->_namespace;
557
        $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
558
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
559
        $metadata->mapManyToMany(array(
560
            'fieldName'     => 'centroCustos',
561
            'targetEntity'  => 'DDC2079CentroCusto',
562
            'joinTable'     => array(
563
                'name'                  => 'unidade_centro_custo',
564
                'joinColumns'           => array(
565
                    array('name' => 'idorcamento',      'referencedColumnName' => 'idorcamento'),
566
                    array('name' => 'idunidade',        'referencedColumnName' => 'idunidade')
567
                ),
568
                'inverseJoinColumns'    => array(
569
                    array('name' => 'idcentrocusto',    'referencedColumnName' => 'idcentrocusto'),
570
                    array('name' => 'idpais',           'referencedColumnName' => 'idpais'),
571
                ),
572
            ),
573
        ));
574
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
575
576
        $filename = $this->_tmpDir . DIRECTORY_SEPARATOR
577
            . $this->_namespace . DIRECTORY_SEPARATOR . 'DDC2079Entity.php';
578
579
        $this->assertFileExists($filename);
580
        require_once $filename;
581
582
        $property   = new \ReflectionProperty($metadata->name, 'centroCustos');
583
        $docComment = $property->getDocComment();
584
585
        //joinColumns
586
        $this->assertContains('@JoinColumn(name="idorcamento", referencedColumnName="idorcamento"),', $docComment);
587
        $this->assertContains('@JoinColumn(name="idunidade", referencedColumnName="idunidade")', $docComment);
588
        //inverseJoinColumns
589
        $this->assertContains('@JoinColumn(name="idcentrocusto", referencedColumnName="idcentrocusto"),', $docComment);
590
        $this->assertContains('@JoinColumn(name="idpais", referencedColumnName="idpais")', $docComment);
591
592
    }
593
594
     /**
595
     * @group DDC-2172
596
     */
597
    public function testGetInheritanceTypeString()
598
    {
599
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadataInfo');
600
        $method     = new \ReflectionMethod($this->_generator, 'getInheritanceTypeString');
601
        $constants  = $reflection->getConstants();
602
        $pattern    = '/^INHERITANCE_TYPE_/';
603
604
        $method->setAccessible(true);
605
606
        foreach ($constants as $name => $value) {
607
            if( ! preg_match($pattern, $name)) {
608
                continue;
609
            }
610
611
            $expected = preg_replace($pattern, '', $name);
612
            $actual   = $method->invoke($this->_generator, $value);
613
614
            $this->assertEquals($expected, $actual);
615
        }
616
617
        $this->setExpectedException('\InvalidArgumentException', 'Invalid provided InheritanceType: INVALID');
618
        $method->invoke($this->_generator, 'INVALID');
619
    }
620
621
    /**
622
    * @group DDC-2172
623
    */
624
    public function testGetChangeTrackingPolicyString()
625
    {
626
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadata');
627
        $method     = new \ReflectionMethod($this->_generator, 'getChangeTrackingPolicyString');
628
        $constants  = $reflection->getConstants();
629
        $pattern    = '/^CHANGETRACKING_/';
630
631
        $method->setAccessible(true);
632
633
        foreach ($constants as $name => $value) {
634
            if( ! preg_match($pattern, $name)) {
635
                continue;
636
            }
637
638
            $expected = preg_replace($pattern, '', $name);
639
            $actual   = $method->invoke($this->_generator, $value);
640
641
            $this->assertEquals($expected, $actual);
642
        }
643
644
        $this->setExpectedException('\InvalidArgumentException', 'Invalid provided ChangeTrackingPolicy: INVALID');
645
        $method->invoke($this->_generator, 'INVALID');
646
    }
647
648
    /**
649
     * @group DDC-2172
650
     */
651
    public function testGetIdGeneratorTypeString()
652
    {
653
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadataInfo');
654
        $method     = new \ReflectionMethod($this->_generator, 'getIdGeneratorTypeString');
655
        $constants  = $reflection->getConstants();
656
        $pattern    = '/^GENERATOR_TYPE_/';
657
658
        $method->setAccessible(true);
659
660
        foreach ($constants as $name => $value) {
661
            if( ! preg_match($pattern, $name)) {
662
                continue;
663
            }
664
665
            $expected = preg_replace($pattern, '', $name);
666
            $actual   = $method->invoke($this->_generator, $value);
667
668
            $this->assertEquals($expected, $actual);
669
        }
670
671
        $this->setExpectedException('\InvalidArgumentException', 'Invalid provided IdGeneratorType: INVALID');
672
        $method->invoke($this->_generator, 'INVALID');
673
    }
674
675
    /**
676
     * @dataProvider getEntityTypeAliasDataProvider
677
     *
678
     * @group DDC-1694
679
     */
680
    public function testEntityTypeAlias(array $field)
681
    {
682
        $metadata   = $this->generateEntityTypeFixture($field);
683
        $path       = $this->_tmpDir . '/'. $this->_namespace . '/EntityType.php';
684
685
        $this->assertFileExists($path);
686
        require_once $path;
687
688
        $entity     = new $metadata->name;
689
        $reflClass  = new \ReflectionClass($metadata->name);
690
691
        $type   = $field['phpType'];
692
        $name   = $field['fieldName'];
693
        $value  = $field['value'];
694
        $getter = "get" . ucfirst($name);
695
        $setter = "set" . ucfirst($name);
696
697
        $this->assertPhpDocVarType($type, $reflClass->getProperty($name));
698
        $this->assertPhpDocParamType($type, $reflClass->getMethod($setter));
699
        $this->assertPhpDocReturnType($type, $reflClass->getMethod($getter));
700
701
        $this->assertSame($entity, $entity->{$setter}($value));
702
        $this->assertEquals($value, $entity->{$getter}());
703
    }
704
705
    /**
706
     * @group DDC-2372
707
     */
708
    public function testTraitPropertiesAndMethodsAreNotDuplicated()
709
    {
710
        $cmf = new ClassMetadataFactory();
711
        $em = $this->_getTestEntityManager();
712
        $cmf->setEntityManager($em);
713
714
        $user = new DDC2372User();
715
        $metadata = $cmf->getMetadataFor(get_class($user));
716
        $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?

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...
717
        $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?

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...
718
719
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
0 ignored issues
show
Compatibility introduced by
$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...
720
721
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/DDC2372User.php");
722
        require $this->_tmpDir . "/" . $this->_namespace . "/DDC2372User.php";
723
724
        $reflClass = new \ReflectionClass($metadata->name);
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?

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...
725
726
        $this->assertSame($reflClass->hasProperty('address'), false);
727
        $this->assertSame($reflClass->hasMethod('setAddress'), false);
728
        $this->assertSame($reflClass->hasMethod('getAddress'), false);
729
    }
730
731
    /**
732
     * @group DDC-2372
733
     */
734
    public function testTraitPropertiesAndMethodsAreNotDuplicatedInChildClasses()
735
    {
736
        $cmf = new ClassMetadataFactory();
737
        $em = $this->_getTestEntityManager();
738
        $cmf->setEntityManager($em);
739
740
        $user = new DDC2372Admin();
741
        $metadata = $cmf->getMetadataFor(get_class($user));
742
        $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?

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...
743
        $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?

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...
744
745
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
0 ignored issues
show
Compatibility introduced by
$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...
746
747
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/DDC2372Admin.php");
748
        require $this->_tmpDir . "/" . $this->_namespace . "/DDC2372Admin.php";
749
750
        $reflClass = new \ReflectionClass($metadata->name);
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?

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...
751
752
        $this->assertSame($reflClass->hasProperty('address'), false);
753
        $this->assertSame($reflClass->hasMethod('setAddress'), false);
754
        $this->assertSame($reflClass->hasMethod('getAddress'), false);
755
    }
756
757
    /**
758
     * @group DDC-1590
759
     */
760
    public function testMethodsAndPropertiesAreNotDuplicatedInChildClasses()
761
    {
762
        $cmf    = new ClassMetadataFactory();
763
        $em     = $this->_getTestEntityManager();
764
765
        $cmf->setEntityManager($em);
766
767
        $ns     = $this->_namespace;
768
        $nsdir  = $this->_tmpDir . '/' . $ns;
769
770
        $content = str_replace(
771
            'namespace Doctrine\Tests\Models\DDC1590',
772
            'namespace ' . $ns,
773
            file_get_contents(__DIR__ . '/../../Models/DDC1590/DDC1590User.php')
774
        );
775
776
        $fname = $nsdir . "/DDC1590User.php";
777
        file_put_contents($fname, $content);
778
        require $fname;
779
780
781
        $metadata = $cmf->getMetadataFor($ns . '\DDC1590User');
782
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
0 ignored issues
show
Compatibility introduced by
$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...
783
784
        // class DDC1590User extends DDC1590Entity { ... }
785
        $source = file_get_contents($fname);
786
787
        // class _DDC1590User extends DDC1590Entity { ... }
788
        $source2    = str_replace('class DDC1590User', 'class _DDC1590User', $source);
789
        $fname2     = $nsdir . "/_DDC1590User.php";
790
        file_put_contents($fname2, $source2);
791
        require $fname2;
792
793
        // class __DDC1590User { ... }
794
        $source3    = str_replace('class DDC1590User extends DDC1590Entity', 'class __DDC1590User', $source);
795
        $fname3     = $nsdir . "/__DDC1590User.php";
796
        file_put_contents($fname3, $source3);
797
        require $fname3;
798
799
800
        // class _DDC1590User extends DDC1590Entity { ... }
801
        $rc2 = new \ReflectionClass($ns.'\_DDC1590User');
802
803
        $this->assertTrue($rc2->hasProperty('name'));
804
        $this->assertTrue($rc2->hasProperty('id'));
805
        $this->assertTrue($rc2->hasProperty('created_at'));
806
807
        $this->assertTrue($rc2->hasMethod('getName'));
808
        $this->assertTrue($rc2->hasMethod('setName'));
809
        $this->assertTrue($rc2->hasMethod('getId'));
810
        $this->assertFalse($rc2->hasMethod('setId'));
811
        $this->assertTrue($rc2->hasMethod('getCreatedAt'));
812
        $this->assertTrue($rc2->hasMethod('setCreatedAt'));
813
814
815
        // class __DDC1590User { ... }
816
        $rc3 = new \ReflectionClass($ns.'\__DDC1590User');
817
818
        $this->assertTrue($rc3->hasProperty('name'));
819
        $this->assertFalse($rc3->hasProperty('id'));
820
        $this->assertFalse($rc3->hasProperty('created_at'));
821
822
        $this->assertTrue($rc3->hasMethod('getName'));
823
        $this->assertTrue($rc3->hasMethod('setName'));
824
        $this->assertFalse($rc3->hasMethod('getId'));
825
        $this->assertFalse($rc3->hasMethod('setId'));
826
        $this->assertFalse($rc3->hasMethod('getCreatedAt'));
827
        $this->assertFalse($rc3->hasMethod('setCreatedAt'));
828
    }
829
830
    /**
831
     * @group DDC-3304
832
     */
833
    public function testGeneratedMutableEmbeddablesClass()
834
    {
835
        $embeddedMetadata = $this->generateTestEmbeddableFixture();
836
        $metadata = $this->generateIsbnEmbeddableFixture(array('test' => $embeddedMetadata));
837
838
        $isbn = $this->newInstance($metadata);
839
840
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
841
        $this->assertFalse(method_exists($metadata->name, '__construct'), "EntityGeneratorIsbn::__construct present.");
842
        $this->assertTrue(method_exists($metadata->name, 'getPrefix'), "EntityGeneratorIsbn::getPrefix() missing.");
843
        $this->assertTrue(method_exists($metadata->name, 'setPrefix'), "EntityGeneratorIsbn::setPrefix() missing.");
844
        $this->assertTrue(method_exists($metadata->name, 'getGroupNumber'), "EntityGeneratorIsbn::getGroupNumber() missing.");
845
        $this->assertTrue(method_exists($metadata->name, 'setGroupNumber'), "EntityGeneratorIsbn::setGroupNumber() missing.");
846
        $this->assertTrue(method_exists($metadata->name, 'getPublisherNumber'), "EntityGeneratorIsbn::getPublisherNumber() missing.");
847
        $this->assertTrue(method_exists($metadata->name, 'setPublisherNumber'), "EntityGeneratorIsbn::setPublisherNumber() missing.");
848
        $this->assertTrue(method_exists($metadata->name, 'getTitleNumber'), "EntityGeneratorIsbn::getTitleNumber() missing.");
849
        $this->assertTrue(method_exists($metadata->name, 'setTitleNumber'), "EntityGeneratorIsbn::setTitleNumber() missing.");
850
        $this->assertTrue(method_exists($metadata->name, 'getCheckDigit'), "EntityGeneratorIsbn::getCheckDigit() missing.");
851
        $this->assertTrue(method_exists($metadata->name, 'setCheckDigit'), "EntityGeneratorIsbn::setCheckDigit() missing.");
852
        $this->assertTrue(method_exists($metadata->name, 'getTest'), "EntityGeneratorIsbn::getTest() missing.");
853
        $this->assertTrue(method_exists($metadata->name, 'setTest'), "EntityGeneratorIsbn::setTest() missing.");
854
855
        $isbn->setPrefix(978);
856
        $this->assertSame(978, $isbn->getPrefix());
857
858
        $this->newInstance($embeddedMetadata);
859
        $test = new $embeddedMetadata->name();
860
861
        $isbn->setTest($test);
862
        $this->assertSame($test, $isbn->getTest());
863
864
        $reflMethod = new \ReflectionMethod($metadata->name, 'setTest');
865
        $reflParameters = $reflMethod->getParameters();
866
        $this->assertEquals($embeddedMetadata->name, $reflParameters[0]->getClass()->name);
867
    }
868
869
    /**
870
     * @group DDC-3304
871
     */
872
    public function testGeneratedImmutableEmbeddablesClass()
873
    {
874
        $this->_generator->setEmbeddablesImmutable(true);
875
        $embeddedMetadata = $this->generateTestEmbeddableFixture();
876
        $metadata = $this->generateIsbnEmbeddableFixture(array('test' => $embeddedMetadata));
877
878
        $this->loadEntityClass($embeddedMetadata);
879
        $this->loadEntityClass($metadata);
880
881
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
882
        $this->assertTrue(method_exists($metadata->name, '__construct'), "EntityGeneratorIsbn::__construct missing.");
883
        $this->assertTrue(method_exists($metadata->name, 'getPrefix'), "EntityGeneratorIsbn::getPrefix() missing.");
884
        $this->assertFalse(method_exists($metadata->name, 'setPrefix'), "EntityGeneratorIsbn::setPrefix() present.");
885
        $this->assertTrue(method_exists($metadata->name, 'getGroupNumber'), "EntityGeneratorIsbn::getGroupNumber() missing.");
886
        $this->assertFalse(method_exists($metadata->name, 'setGroupNumber'), "EntityGeneratorIsbn::setGroupNumber() present.");
887
        $this->assertTrue(method_exists($metadata->name, 'getPublisherNumber'), "EntityGeneratorIsbn::getPublisherNumber() missing.");
888
        $this->assertFalse(method_exists($metadata->name, 'setPublisherNumber'), "EntityGeneratorIsbn::setPublisherNumber() present.");
889
        $this->assertTrue(method_exists($metadata->name, 'getTitleNumber'), "EntityGeneratorIsbn::getTitleNumber() missing.");
890
        $this->assertFalse(method_exists($metadata->name, 'setTitleNumber'), "EntityGeneratorIsbn::setTitleNumber() present.");
891
        $this->assertTrue(method_exists($metadata->name, 'getCheckDigit'), "EntityGeneratorIsbn::getCheckDigit() missing.");
892
        $this->assertFalse(method_exists($metadata->name, 'setCheckDigit'), "EntityGeneratorIsbn::setCheckDigit() present.");
893
        $this->assertTrue(method_exists($metadata->name, 'getTest'), "EntityGeneratorIsbn::getTest() missing.");
894
        $this->assertFalse(method_exists($metadata->name, 'setTest'), "EntityGeneratorIsbn::setTest() present.");
895
896
        $test = new $embeddedMetadata->name(1, new \DateTime());
897
        $isbn = new $metadata->name($test, 978, 3, 12, 732320, 83);
898
899
        $reflMethod = new \ReflectionMethod($isbn, '__construct');
900
        $reflParameters = $reflMethod->getParameters();
901
902
        $this->assertCount(6, $reflParameters);
903
904
        $this->assertSame($embeddedMetadata->name, $reflParameters[0]->getClass()->name);
905
        $this->assertSame('test', $reflParameters[0]->getName());
906
        $this->assertFalse($reflParameters[0]->isOptional());
907
908
        $this->assertSame('prefix', $reflParameters[1]->getName());
909
        $this->assertFalse($reflParameters[1]->isOptional());
910
911
        $this->assertSame('groupNumber', $reflParameters[2]->getName());
912
        $this->assertFalse($reflParameters[2]->isOptional());
913
914
        $this->assertSame('publisherNumber', $reflParameters[3]->getName());
915
        $this->assertFalse($reflParameters[3]->isOptional());
916
917
        $this->assertSame('titleNumber', $reflParameters[4]->getName());
918
        $this->assertFalse($reflParameters[4]->isOptional());
919
920
        $this->assertSame('checkDigit', $reflParameters[5]->getName());
921
        $this->assertFalse($reflParameters[5]->isOptional());
922
923
        $reflMethod = new \ReflectionMethod($test, '__construct');
924
        $reflParameters = $reflMethod->getParameters();
925
926
        $this->assertCount(4, $reflParameters);
927
928
        $this->assertSame('field1', $reflParameters[0]->getName());
929
        $this->assertFalse($reflParameters[0]->isOptional());
930
931
        $this->assertSame('DateTime', $reflParameters[1]->getClass()->name);
932
        $this->assertSame('field3', $reflParameters[1]->getName());
933
        $this->assertFalse($reflParameters[1]->isOptional());
934
935
        $this->assertSame('field2', $reflParameters[2]->getName());
936
        $this->assertTrue($reflParameters[2]->isOptional());
937
938
        $this->assertSame('DateTime', $reflParameters[3]->getClass()->name);
939
        $this->assertSame('field4', $reflParameters[3]->getName());
940
        $this->assertTrue($reflParameters[3]->isOptional());
941
    }
942
943
    public function testRegenerateEntityClass()
944
    {
945
        $metadata = $this->generateBookEntityFixture();
946
        $this->loadEntityClass($metadata);
947
948
        $className = basename(str_replace('\\', '/', $metadata->name));
949
        $path = $this->_tmpDir . '/' . $this->_namespace . '/' . $className . '.php';
950
        $classTest = file_get_contents($path);
951
952
        $this->_generator->setRegenerateEntityIfExists(true);
953
        $this->_generator->setBackupExisting(false);
954
955
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
956
        $classNew = file_get_contents($path);
957
958
        $this->assertSame($classTest,$classNew);
959
    }
960
961
    public function testGenerateMethodsTypeHinting()
962
    {
963
        if (version_compare(PHP_VERSION, '7.0.0', '<')) {
964
            $this->markTestSkipped('Scalar type hinting and method return types are available in PHP >= 7.0.0');
965
        }
966
967
        $this->_generator->setGenerateMethodsTypeHinting(true);
968
969
        $metadata = $this->generateBookEntityFixture();
970
        $this->loadEntityClass($metadata);
971
972
        $reflClass = new \ReflectionClass($metadata->name);
973
974
        $this->assertCount(5, $reflClass->getProperties());
975
        $this->assertCount(13, $reflClass->getMethods());
976
977
        $reflMethod = new \ReflectionMethod($metadata->name, 'getId');
978
        $this->assertEquals('int', $reflMethod->getReturnType());
979
980
        $reflMethod = new \ReflectionMethod($metadata->name, 'setName');
981
        $parameters = $reflMethod->getParameters();
982
        $this->assertEquals(1, count($parameters));
983
        $this->assertEquals('string', $parameters[0]->getType());
984
        $this->assertEquals('self', $reflMethod->getReturnType());
985
986
        $reflMethod = new \ReflectionMethod($metadata->name, 'getName');
987
        $this->assertEquals('string', $reflMethod->getReturnType());
988
989
        $reflMethod = new \ReflectionMethod($metadata->name, 'setStatus');
990
        $parameters = $reflMethod->getParameters();
991
        $this->assertEquals(1, count($parameters));
992
        $this->assertEquals('string', $parameters[0]->getType());
993
        $this->assertEquals('self', $reflMethod->getReturnType());
994
995
        $reflMethod = new \ReflectionMethod($metadata->name, 'getStatus');
996
        $this->assertEquals('string', $reflMethod->getReturnType());
997
998
        $authorClass = get_class(new EntityGeneratorAuthor());
999
        $reflMethod = new \ReflectionMethod($metadata->name, 'setAuthor');
1000
        $parameters = $reflMethod->getParameters();
1001
        $this->assertEquals(1, count($parameters));
1002
        $this->assertEquals($authorClass, (string) $parameters[0]->getType());
1003
        $this->assertEquals('self', $reflMethod->getReturnType());
1004
1005
        $reflMethod = new \ReflectionMethod($metadata->name, 'getAuthor');
1006
        $this->assertNull($reflMethod->getReturnType());
1007
1008
        $reflMethod = new \ReflectionMethod($metadata->name, 'addComment');
1009
        $this->assertEquals('self', $reflMethod->getReturnType());
1010
1011
        $reflMethod = new \ReflectionMethod($metadata->name, 'removeComment');
1012
        $this->assertEquals('bool', $reflMethod->getReturnType());
1013
1014
        $reflMethod = new \ReflectionMethod($metadata->name, 'getComments');
1015
        $this->assertEquals('Doctrine\Common\Collections\Collection', $reflMethod->getReturnType());
1016
1017
        $reflMethod = new \ReflectionMethod($metadata->name, 'loading');
1018
        $this->assertNull($reflMethod->getReturnType());
1019
1020
        $reflMethod = new \ReflectionMethod($metadata->name, 'willBeRemoved');
1021
        $this->assertNull($reflMethod->getReturnType());
1022
    }
1023
1024
    /**
1025
     * @dataProvider getEntityTypeAliasDataProvider
1026
     */
1027
    public function testEntityMethodTypeHintingAlias(array $field)
1028
    {
1029
        if (version_compare(PHP_VERSION, '7.0.0', '<')) {
1030
            $this->markTestSkipped('Scalar type hinting and method return types are available in PHP >= 7.0.0');
1031
        }
1032
1033
        $this->_generator->setGenerateMethodsTypeHinting(true);
1034
1035
        $metadata   = $this->generateEntityTypeFixture($field);
1036
        $path       = $this->_tmpDir . '/'. $this->_namespace . '/EntityType.php';
1037
1038
        $this->assertFileExists($path);
1039
        require_once $path;
1040
1041
        $type   = $field['phpType'];
1042
        if ('\\' === $type[0]) {
1043
            $type = substr($type, 1);
1044
        }
1045
1046
        $name   = $field['fieldName'];
1047
        $getter = "get" . ucfirst($name);
1048
        $setter = "set" . ucfirst($name);
1049
1050
        $reflMethod = new \ReflectionMethod($metadata->name, $setter);
1051
        $parameters = $reflMethod->getParameters();
1052
        $this->assertEquals(1, count($parameters));
1053
        $this->assertEquals($type, $parameters[0]->getType());
1054
        $this->assertEquals('self', $reflMethod->getReturnType());
1055
1056
        $reflMethod = new \ReflectionMethod($metadata->name, $getter);
1057
        $this->assertEquals($type, (string) $reflMethod->getReturnType());
1058
    }
1059
1060
    /**
1061
     * @return array
1062
     */
1063
    public function getEntityTypeAliasDataProvider()
1064
    {
1065
        return array(
1066
            array(array(
1067
                'fieldName' => 'datetimetz',
1068
                'phpType' => '\\DateTime',
1069
                'dbType' => 'datetimetz',
1070
                'value' => new \DateTime
1071
            )),
1072
            array(array(
1073
                'fieldName' => 'datetime',
1074
                'phpType' => '\\DateTime',
1075
                'dbType' => 'datetime',
1076
                'value' => new \DateTime
1077
            )),
1078
            array(array(
1079
                'fieldName' => 'date',
1080
                'phpType' => '\\DateTime',
1081
                'dbType' => 'date',
1082
                'value' => new \DateTime
1083
            )),
1084
            array(array(
1085
                'fieldName' => 'time',
1086
                'phpType' => '\DateTime',
1087
                'dbType' => 'time',
1088
                'value' => new \DateTime
1089
            )),
1090
            array(array(
1091
                'fieldName' => 'object',
1092
                'phpType' => '\stdClass',
1093
                'dbType' => 'object',
1094
                'value' => new \stdClass()
1095
            )),
1096
            array(array(
1097
                'fieldName' => 'bigint',
1098
                'phpType' => 'int',
1099
                'dbType' => 'bigint',
1100
                'value' => 11
1101
            )),
1102
            array(array(
1103
                'fieldName' => 'smallint',
1104
                'phpType' => 'int',
1105
                'dbType' => 'smallint',
1106
                'value' => 22
1107
            )),
1108
            array(array(
1109
                'fieldName' => 'text',
1110
                'phpType' => 'string',
1111
                'dbType' => 'text',
1112
                'value' => 'text'
1113
            )),
1114
            array(array(
1115
                'fieldName' => 'blob',
1116
                'phpType' => 'string',
1117
                'dbType' => 'blob',
1118
                'value' => 'blob'
1119
            )),
1120
            array(array(
1121
                'fieldName' => 'decimal',
1122
                'phpType' => 'string',
1123
                'dbType' => 'decimal',
1124
                'value' => '12.34'
1125
            ),
1126
        ));
1127
    }
1128
1129
    public function getParseTokensInEntityFileData()
1130
    {
1131
        return array(
1132
            array(
1133
                '<?php namespace Foo\Bar; class Baz {}',
1134
                array('Foo\Bar\Baz'),
1135
            ),
1136
            array(
1137
                '<?php namespace Foo\Bar; use Foo; class Baz {}',
1138
                array('Foo\Bar\Baz'),
1139
            ),
1140
            array(
1141
                '<?php namespace /*Comment*/ Foo\Bar; /** Foo */class /* Comment */ Baz {}',
1142
                array('Foo\Bar\Baz'),
1143
            ),
1144
            array(
1145
                '
1146
<?php namespace
1147
/*Comment*/
1148
Foo\Bar
1149
;
1150
1151
/** Foo */
1152
class
1153
/* Comment */
1154
 Baz {}
1155
     ',
1156
                array('Foo\Bar\Baz'),
1157
            ),
1158
            array(
1159
                '
1160
<?php namespace Foo\Bar; class Baz {
1161
    public static function someMethod(){
1162
        return self::class;
1163
    }
1164
}
1165
',
1166
                array('Foo\Bar\Baz'),
1167
            ),
1168
        );
1169
    }
1170
1171
    /**
1172
     * @param string $type
1173
     * @param \ReflectionProperty $property
1174
     */
1175
    private function assertPhpDocVarType($type, \ReflectionProperty $property)
1176
    {
1177
        $this->assertEquals(1, preg_match('/@var\s+([^\s]+)/',$property->getDocComment(), $matches));
1178
        $this->assertEquals($type, $matches[1]);
1179
    }
1180
1181
    /**
1182
     * @param string $type
1183
     * @param \ReflectionProperty $method
1184
     */
1185
    private function assertPhpDocReturnType($type, \ReflectionMethod $method)
1186
    {
1187
        $this->assertEquals(1, preg_match('/@return\s+([^\s]+)/', $method->getDocComment(), $matches));
1188
        $this->assertEquals($type, $matches[1]);
1189
    }
1190
1191
    /**
1192
     * @param string $type
1193
     * @param \ReflectionProperty $method
1194
     */
1195
    private function assertPhpDocParamType($type, \ReflectionMethod $method)
1196
    {
1197
        $this->assertEquals(1, preg_match('/@param\s+([^\s]+)/', $method->getDocComment(), $matches));
1198
        $this->assertEquals($type, $matches[1]);
1199
    }
1200
}
1201
1202
class EntityGeneratorAuthor {}
1203
class EntityGeneratorComment {}
1204