Completed
Pull Request — master (#5883)
by Sebastian
19:21
created

testGetChangeTrackingPolicyString()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 25
rs 8.8571
cc 3
eloc 15
nc 3
nop 0
1
<?php
2
3
namespace Doctrine\Tests\ORM\Tools;
4
5
use Doctrine\Common\Annotations\AnnotationReader;
6
use Doctrine\Common\Collections\ArrayCollection;
7
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
8
use Doctrine\ORM\Mapping\ClassMetadataFactory;
9
use Doctrine\ORM\Mapping\ClassMetadataInfo;
10
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
11
use Doctrine\ORM\Tools\EntityGenerator;
12
use Doctrine\Tests\Models\DDC2372\DDC2372Admin;
13
use Doctrine\Tests\Models\DDC2372\DDC2372User;
14
use Doctrine\Tests\OrmTestCase;
15
16
class EntityGeneratorTest extends OrmTestCase
17
{
18
19
    /**
20
     * @var EntityGenerator
21
     */
22
    private $_generator;
23
    private $_tmpDir;
24
    private $_namespace;
25
26
    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 = array())
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'] = array('columns' => array('name'));
65
        $metadata->table['indexes']['status_idx'] = array('columns' => array('status'));
66
        $metadata->mapField(array('fieldName' => 'name', 'type' => 'string'));
67
        $metadata->mapField(array('fieldName' => 'status', 'type' => 'string', 'options' => array('default' => 'published')));
68
        $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
69
        $metadata->mapOneToOne(array('fieldName' => 'author', 'targetEntity' => 'Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', 'mappedBy' => 'book'));
70
        $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...
71
            array('name' => 'author_id', 'referencedColumnName' => 'id')
72
        );
73
        $metadata->mapManyToMany(array(
74
            'fieldName' => 'comments',
75
            'targetEntity' => 'Doctrine\Tests\ORM\Tools\EntityGeneratorComment',
76
            'fetch' => ClassMetadataInfo::FETCH_EXTRA_LAZY,
77
            'joinTable' => array(
78
                'name' => 'book_comment',
79
                'joinColumns' => array(array('name' => 'book_id', 'referencedColumnName' => 'id')),
80
                'inverseJoinColumns' => array(array('name' => 'comment_id', 'referencedColumnName' => 'id')),
81
            ),
82
        ));
83
        $metadata->addLifecycleCallback('loading', 'postLoad');
84
        $metadata->addLifecycleCallback('willBeRemoved', 'preRemove');
85
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
86
87
        foreach ($embeddedClasses as $fieldName => $embeddedClass) {
88
            $this->mapNestedEmbedded($fieldName, $metadata, $embeddedClass);
89
            $this->mapEmbedded($fieldName, $metadata, $embeddedClass);
90
        }
91
92
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
93
94
        return $metadata;
95
    }
96
97
    private function generateEntityTypeFixture(array $field)
98
    {
99
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityType');
100
        $metadata->namespace = $this->_namespace;
101
102
        $metadata->table['name'] = 'entity_type';
103
        $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
104
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
105
106
        $name  = $field['fieldName'];
107
        $type  = $field['dbType'];
108
        $metadata->mapField(array('fieldName' => $name, 'type' => $type));
109
110
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
111
112
        return $metadata;
113
    }
114
115
    /**
116
     * @return ClassMetadataInfo
117
     */
118
    private function generateIsbnEmbeddableFixture(array $embeddedClasses = array())
119
    {
120
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorIsbn');
121
        $metadata->namespace = $this->_namespace;
122
        $metadata->isEmbeddedClass = true;
123
        $metadata->mapField(array('fieldName' => 'prefix', 'type' => 'integer'));
124
        $metadata->mapField(array('fieldName' => 'groupNumber', 'type' => 'integer'));
125
        $metadata->mapField(array('fieldName' => 'publisherNumber', 'type' => 'integer'));
126
        $metadata->mapField(array('fieldName' => 'titleNumber', 'type' => 'integer'));
127
        $metadata->mapField(array('fieldName' => 'checkDigit', 'type' => 'integer'));
128
129
        foreach ($embeddedClasses as $fieldName => $embeddedClass) {
130
            $this->mapEmbedded($fieldName, $metadata, $embeddedClass);
131
        }
132
133
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
134
135
        return $metadata;
136
    }
137
138
    /**
139
     * @return ClassMetadataInfo
140
     */
141
    private function generateTestEmbeddableFixture()
142
    {
143
        $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorTestEmbeddable');
144
        $metadata->namespace = $this->_namespace;
145
        $metadata->isEmbeddedClass = true;
146
        $metadata->mapField(array('fieldName' => 'field1', 'type' => 'integer'));
147
        $metadata->mapField(array('fieldName' => 'field2', 'type' => 'integer', 'nullable' => true));
148
        $metadata->mapField(array('fieldName' => 'field3', 'type' => 'datetime'));
149
        $metadata->mapField(array('fieldName' => 'field4', 'type' => 'datetime', 'nullable' => true));
150
151
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
152
153
        return $metadata;
154
    }
155
156
    /**
157
     * @param string            $fieldName
158
     * @param ClassMetadataInfo $classMetadata
159
     * @param ClassMetadataInfo $embeddableMetadata
160
     * @param string|null       $columnPrefix
161
     */
162
    private function mapEmbedded(
163
        $fieldName,
164
        ClassMetadataInfo $classMetadata,
165
        ClassMetadataInfo $embeddableMetadata,
166
        $columnPrefix = false
167
    ) {
168
        $classMetadata->mapEmbedded(
169
            array('fieldName' => $fieldName, 'class' => $embeddableMetadata->name, 'columnPrefix' => $columnPrefix)
170
        );
171
    }
172
173
    /**
174
     * @param string            $fieldName
175
     * @param ClassMetadataInfo $classMetadata
176
     * @param ClassMetadataInfo $embeddableMetadata
177
     */
178
    private function mapNestedEmbedded(
179
        $fieldName,
180
        ClassMetadataInfo $classMetadata,
181
        ClassMetadataInfo $embeddableMetadata
182
    ) {
183
        foreach ($embeddableMetadata->embeddedClasses as $property => $embeddableClass) {
184
            $classMetadata->mapEmbedded(array(
185
                'fieldName' => $fieldName . '.' . $property,
186
                'class' => $embeddableClass['class'],
187
                'columnPrefix' => $embeddableClass['columnPrefix'],
188
                'declaredField' => $embeddableClass['declaredField']
189
                        ? $fieldName . '.' . $embeddableClass['declaredField']
190
                        : $fieldName,
191
                'originalField' => $embeddableClass['originalField'] ?: $property,
192
            ));
193
        }
194
    }
195
196
    /**
197
     * @param ClassMetadataInfo $metadata
198
     */
199
    private function loadEntityClass(ClassMetadataInfo $metadata)
200
    {
201
        $className = basename(str_replace('\\', '/', $metadata->name));
202
        $path = $this->_tmpDir . '/' . $this->_namespace . '/' . $className . '.php';
203
204
        $this->assertFileExists($path);
205
206
        require_once $path;
207
    }
208
209
    /**
210
     * @param  ClassMetadataInfo $metadata
211
     *
212
     * @return mixed An instance of the given metadata's class.
213
     */
214
    public function newInstance($metadata)
215
    {
216
        $this->loadEntityClass($metadata);
217
218
        return new $metadata->name;
219
    }
220
221
    public function testGeneratedEntityClass()
222
    {
223
        $testMetadata = $this->generateTestEmbeddableFixture();
224
        $isbnMetadata = $this->generateIsbnEmbeddableFixture(array('test' => $testMetadata));
225
        $metadata = $this->generateBookEntityFixture(array('isbn' => $isbnMetadata));
226
227
        $book = $this->newInstance($metadata);
228
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
229
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', '__construct'), "EntityGeneratorBook::__construct() missing.");
230
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getId'), "EntityGeneratorBook::getId() missing.");
231
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setName'), "EntityGeneratorBook::setName() missing.");
232
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getName'), "EntityGeneratorBook::getName() missing.");
233
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setStatus'), "EntityGeneratorBook::setStatus() missing.");
234
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getStatus'), "EntityGeneratorBook::getStatus() missing.");
235
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setAuthor'), "EntityGeneratorBook::setAuthor() missing.");
236
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getAuthor'), "EntityGeneratorBook::getAuthor() missing.");
237
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getComments'), "EntityGeneratorBook::getComments() missing.");
238
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'addComment'), "EntityGeneratorBook::addComment() missing.");
239
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'removeComment'), "EntityGeneratorBook::removeComment() missing.");
240
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setIsbn'), "EntityGeneratorBook::setIsbn() missing.");
241
        $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getIsbn'), "EntityGeneratorBook::getIsbn() missing.");
242
243
        $reflClass = new \ReflectionClass($metadata->name);
244
245
        $this->assertCount(6, $reflClass->getProperties());
246
        $this->assertCount(15, $reflClass->getMethods());
247
248
        $this->assertEquals('published', $book->getStatus());
249
250
        $book->setName('Jonathan H. Wage');
251
        $this->assertEquals('Jonathan H. Wage', $book->getName());
252
253
        $reflMethod = new \ReflectionMethod($metadata->name, 'addComment');
254
        $addCommentParameters = $reflMethod->getParameters();
255
        $this->assertEquals('comment', $addCommentParameters[0]->getName());
0 ignored issues
show
Bug introduced by
Consider using $addCommentParameters[0]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
256
257
        $reflMethod = new \ReflectionMethod($metadata->name, 'removeComment');
258
        $removeCommentParameters = $reflMethod->getParameters();
259
        $this->assertEquals('comment', $removeCommentParameters[0]->getName());
0 ignored issues
show
Bug introduced by
Consider using $removeCommentParameters[0]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
260
261
        $author = new EntityGeneratorAuthor();
262
        $book->setAuthor($author);
263
        $this->assertEquals($author, $book->getAuthor());
264
265
        $comment = new EntityGeneratorComment();
266
        $this->assertInstanceOf($metadata->name, $book->addComment($comment));
267
        $this->assertInstanceOf('Doctrine\Common\Collections\ArrayCollection', $book->getComments());
268
        $this->assertEquals(new ArrayCollection(array($comment)), $book->getComments());
269
        $this->assertInternalType('boolean', $book->removeComment($comment));
270
        $this->assertEquals(new ArrayCollection(array()), $book->getComments());
271
272
        $this->newInstance($isbnMetadata);
273
        $isbn = new $isbnMetadata->name();
274
275
        $book->setIsbn($isbn);
276
        $this->assertSame($isbn, $book->getIsbn());
277
278
        $reflMethod = new \ReflectionMethod($metadata->name, 'setIsbn');
279
        $reflParameters = $reflMethod->getParameters();
280
        $this->assertEquals($isbnMetadata->name, $reflParameters[0]->getClass()->name);
281
    }
282
283
    public function testEntityUpdatingWorks()
284
    {
285
        $metadata = $this->generateBookEntityFixture(array('isbn' => $this->generateIsbnEmbeddableFixture()));
286
287
        $metadata->mapField(array('fieldName' => 'test', 'type' => 'string'));
288
289
        $testEmbeddableMetadata = $this->generateTestEmbeddableFixture();
290
        $this->mapEmbedded('testEmbedded', $metadata, $testEmbeddableMetadata);
291
292
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
293
294
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
295
296
        $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...
297
        $reflClass = new \ReflectionClass($metadata->name);
298
299
        $this->assertTrue($reflClass->hasProperty('name'), "Regenerating keeps property 'name'.");
300
        $this->assertTrue($reflClass->hasProperty('status'), "Regenerating keeps property 'status'.");
301
        $this->assertTrue($reflClass->hasProperty('id'), "Regenerating keeps property 'id'.");
302
        $this->assertTrue($reflClass->hasProperty('isbn'), "Regenerating keeps property 'isbn'.");
303
304
        $this->assertTrue($reflClass->hasProperty('test'), "Check for property test failed.");
305
        $this->assertTrue($reflClass->getProperty('test')->isProtected(), "Check for protected property test failed.");
306
        $this->assertTrue($reflClass->hasProperty('testEmbedded'), "Check for property testEmbedded failed.");
307
        $this->assertTrue($reflClass->getProperty('testEmbedded')->isProtected(), "Check for protected property testEmbedded failed.");
308
        $this->assertTrue($reflClass->hasMethod('getTest'), "Check for method 'getTest' failed.");
309
        $this->assertTrue($reflClass->getMethod('getTest')->isPublic(), "Check for public visibility of method 'getTest' failed.");
310
        $this->assertTrue($reflClass->hasMethod('setTest'), "Check for method 'setTest' failed.");
311
        $this->assertTrue($reflClass->getMethod('setTest')->isPublic(), "Check for public visibility of method 'setTest' failed.");
312
        $this->assertTrue($reflClass->hasMethod('getTestEmbedded'), "Check for method 'getTestEmbedded' failed.");
313
        $this->assertTrue(
314
            $reflClass->getMethod('getTestEmbedded')->isPublic(),
315
            "Check for public visibility of method 'getTestEmbedded' failed."
316
        );
317
        $this->assertTrue($reflClass->hasMethod('setTestEmbedded'), "Check for method 'setTestEmbedded' failed.");
318
        $this->assertTrue(
319
            $reflClass->getMethod('setTestEmbedded')->isPublic(),
320
            "Check for public visibility of method 'setTestEmbedded' failed."
321
        );
322
    }
323
324
    /**
325
     * @group DDC-3152
326
     */
327
    public function testDoesNotRegenerateExistingMethodsWithDifferentCase()
328
    {
329
        $metadata = $this->generateBookEntityFixture(array('isbn' => $this->generateIsbnEmbeddableFixture()));
330
331
        // Workaround to change existing fields case (just to simulate the use case)
332
        $metadata->fieldMappings['status']['fieldName'] = 'STATUS';
333
        $metadata->embeddedClasses['ISBN'] = $metadata->embeddedClasses['isbn'];
334
        unset($metadata->embeddedClasses['isbn']);
335
336
        // Should not throw a PHP fatal error
337
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
338
339
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
340
341
        $this->newInstance($metadata);
342
        $reflClass = new \ReflectionClass($metadata->name);
343
344
        $this->assertTrue($reflClass->hasProperty('status'));
345
        $this->assertTrue($reflClass->hasProperty('STATUS'));
346
        $this->assertTrue($reflClass->hasProperty('isbn'));
347
        $this->assertTrue($reflClass->hasProperty('ISBN'));
348
        $this->assertTrue($reflClass->hasMethod('getStatus'));
349
        $this->assertTrue($reflClass->hasMethod('setStatus'));
350
        $this->assertTrue($reflClass->hasMethod('getIsbn'));
351
        $this->assertTrue($reflClass->hasMethod('setIsbn'));
352
    }
353
354
    /**
355
     * @group DDC-2121
356
     */
357
    public function testMethodDocBlockShouldStartWithBackSlash()
358
    {
359
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
360
        $metadata = $this->generateBookEntityFixture(array('isbn' => $embeddedMetadata));
361
        $book     = $this->newInstance($metadata);
362
363
        $this->assertPhpDocVarType('\Doctrine\Common\Collections\Collection', new \ReflectionProperty($book, 'comments'));
364
        $this->assertPhpDocReturnType('\Doctrine\Common\Collections\Collection', new \ReflectionMethod($book, 'getComments'));
365
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorComment', new \ReflectionMethod($book, 'addComment'));
366
        $this->assertPhpDocReturnType('EntityGeneratorBook', new \ReflectionMethod($book, 'addComment'));
367
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorComment', new \ReflectionMethod($book, 'removeComment'));
368
        $this->assertPhpDocReturnType('boolean', new \ReflectionMethod($book, 'removeComment'));
369
370
        $this->assertPhpDocVarType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', new \ReflectionProperty($book, 'author'));
371
        $this->assertPhpDocReturnType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', new \ReflectionMethod($book, 'getAuthor'));
372
        $this->assertPhpDocParamType('\Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', new \ReflectionMethod($book, 'setAuthor'));
373
374
        $expectedClassName = '\\' . $embeddedMetadata->name;
375
        $this->assertPhpDocVarType($expectedClassName, new \ReflectionProperty($book, 'isbn'));
376
        $this->assertPhpDocReturnType($expectedClassName, new \ReflectionMethod($book, 'getIsbn'));
377
        $this->assertPhpDocParamType($expectedClassName, new \ReflectionMethod($book, 'setIsbn'));
378
    }
379
380
    public function testEntityExtendsStdClass()
381
    {
382
        $this->_generator->setClassToExtend('stdClass');
383
        $metadata = $this->generateBookEntityFixture();
384
385
        $book = $this->newInstance($metadata);
386
        $this->assertInstanceOf('stdClass', $book);
387
388
        $metadata = $this->generateIsbnEmbeddableFixture();
389
        $isbn = $this->newInstance($metadata);
390
        $this->assertInstanceOf('stdClass', $isbn);
391
    }
392
393
    public function testLifecycleCallbacks()
394
    {
395
        $metadata = $this->generateBookEntityFixture();
396
397
        $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...
398
        $reflClass = new \ReflectionClass($metadata->name);
399
400
        $this->assertTrue($reflClass->hasMethod('loading'), "Check for postLoad lifecycle callback.");
401
        $this->assertTrue($reflClass->hasMethod('willBeRemoved'), "Check for preRemove lifecycle callback.");
402
    }
403
404
    public function testLoadMetadata()
405
    {
406
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
407
        $metadata = $this->generateBookEntityFixture(array('isbn' => $embeddedMetadata));
408
409
        $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...
410
411
        $reflectionService = new RuntimeReflectionService();
412
413
        $cm = new ClassMetadataInfo($metadata->name);
414
        $cm->initializeReflection($reflectionService);
415
416
        $driver = $this->createAnnotationDriver();
417
        $driver->loadMetadataForClass($cm->name, $cm);
418
419
        $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...
420
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
421
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
422
        $this->assertEquals($cm->identifier, $metadata->identifier);
423
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
424
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
425
        $this->assertEquals($cm->embeddedClasses, $metadata->embeddedClasses);
426
        $this->assertEquals($cm->isEmbeddedClass, $metadata->isEmbeddedClass);
427
428
        $this->assertEquals(ClassMetadataInfo::FETCH_EXTRA_LAZY, $cm->associationMappings['comments']['fetch']);
429
430
        $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...
431
432
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
433
        $cm->initializeReflection($reflectionService);
434
435
        $driver->loadMetadataForClass($cm->name, $cm);
436
437
        $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...
438
        $this->assertEquals($cm->embeddedClasses, $embeddedMetadata->embeddedClasses);
439
        $this->assertEquals($cm->isEmbeddedClass, $embeddedMetadata->isEmbeddedClass);
440
    }
441
442
    public function testLoadPrefixedMetadata()
443
    {
444
        $this->_generator->setAnnotationPrefix('ORM\\');
445
        $embeddedMetadata = $this->generateIsbnEmbeddableFixture();
446
        $metadata = $this->generateBookEntityFixture(array('isbn' => $embeddedMetadata));
447
448
        $reader = new AnnotationReader();
449
        $driver = new AnnotationDriver($reader, array());
450
451
        $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...
452
453
        $reflectionService = new RuntimeReflectionService();
454
455
        $cm = new ClassMetadataInfo($metadata->name);
456
        $cm->initializeReflection($reflectionService);
457
458
        $driver->loadMetadataForClass($cm->name, $cm);
459
460
        $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...
461
        $this->assertEquals($cm->getTableName(), $metadata->getTableName());
462
        $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
463
        $this->assertEquals($cm->identifier, $metadata->identifier);
464
        $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
465
        $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
466
467
        $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...
468
469
        $cm = new ClassMetadataInfo($embeddedMetadata->name);
470
        $cm->initializeReflection($reflectionService);
471
472
        $driver->loadMetadataForClass($cm->name, $cm);
473
474
        $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...
475
        $this->assertEquals($cm->embeddedClasses, $embeddedMetadata->embeddedClasses);
476
        $this->assertEquals($cm->isEmbeddedClass, $embeddedMetadata->isEmbeddedClass);
477
    }
478
479
    /**
480
     * @group DDC-3272
481
     */
482
    public function testMappedSuperclassAnnotationGeneration()
483
    {
484
        $metadata                     = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorBook');
485
        $metadata->namespace          = $this->_namespace;
486
        $metadata->isMappedSuperclass = true;
487
488
        $this->_generator->setAnnotationPrefix('ORM\\');
489
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
490
        $this->newInstance($metadata); // force instantiation (causes autoloading to kick in)
491
492
        $driver = new AnnotationDriver(new AnnotationReader(), array());
493
        $cm     = new ClassMetadataInfo($metadata->name);
494
495
        $cm->initializeReflection(new RuntimeReflectionService);
496
        $driver->loadMetadataForClass($cm->name, $cm);
497
498
        $this->assertTrue($cm->isMappedSuperclass);
499
    }
500
501
    /**
502
     * @dataProvider getParseTokensInEntityFileData
503
     */
504
    public function testParseTokensInEntityFile($php, $classes)
505
    {
506
        $r = new \ReflectionObject($this->_generator);
507
        $m = $r->getMethod('parseTokensInEntityFile');
508
        $m->setAccessible(true);
509
510
        $p = $r->getProperty('staticReflection');
511
        $p->setAccessible(true);
512
513
        $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...
514
        $this->assertEquals($classes, array_keys($p->getValue($this->_generator)));
515
    }
516
517
    /**
518
     * @group DDC-1784
519
     */
520
    public function testGenerateEntityWithSequenceGenerator()
521
    {
522
        $metadata               = new ClassMetadataInfo($this->_namespace . '\DDC1784Entity');
523
        $metadata->namespace    = $this->_namespace;
524
        $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
525
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
526
        $metadata->setSequenceGeneratorDefinition(array(
527
            'sequenceName'      => 'DDC1784_ID_SEQ',
528
            'allocationSize'    => 1,
529
            'initialValue'      => 2
530
        ));
531
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
532
533
        $filename = $this->_tmpDir . DIRECTORY_SEPARATOR
534
                  . $this->_namespace . DIRECTORY_SEPARATOR . 'DDC1784Entity.php';
535
536
        $this->assertFileExists($filename);
537
        require_once $filename;
538
539
540
        $reflection = new \ReflectionProperty($metadata->name, 'id');
541
        $docComment = $reflection->getDocComment();
542
543
        $this->assertContains('@Id', $docComment);
544
        $this->assertContains('@Column(name="id", type="integer")', $docComment);
545
        $this->assertContains('@GeneratedValue(strategy="SEQUENCE")', $docComment);
546
        $this->assertContains('@SequenceGenerator(sequenceName="DDC1784_ID_SEQ", allocationSize=1, initialValue=2)', $docComment);
547
    }
548
549
    /**
550
     * @group DDC-2079
551
     */
552
    public function testGenerateEntityWithMultipleInverseJoinColumns()
553
    {
554
        $metadata               = new ClassMetadataInfo($this->_namespace . '\DDC2079Entity');
555
        $metadata->namespace    = $this->_namespace;
556
        $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
557
        $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
558
        $metadata->mapManyToMany(array(
559
            'fieldName'     => 'centroCustos',
560
            'targetEntity'  => 'DDC2079CentroCusto',
561
            'joinTable'     => array(
562
                'name'                  => 'unidade_centro_custo',
563
                'joinColumns'           => array(
564
                    array('name' => 'idorcamento',      'referencedColumnName' => 'idorcamento'),
565
                    array('name' => 'idunidade',        'referencedColumnName' => 'idunidade')
566
                ),
567
                'inverseJoinColumns'    => array(
568
                    array('name' => 'idcentrocusto',    'referencedColumnName' => 'idcentrocusto'),
569
                    array('name' => 'idpais',           'referencedColumnName' => 'idpais'),
570
                ),
571
            ),
572
        ));
573
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
574
575
        $filename = $this->_tmpDir . DIRECTORY_SEPARATOR
576
            . $this->_namespace . DIRECTORY_SEPARATOR . 'DDC2079Entity.php';
577
578
        $this->assertFileExists($filename);
579
        require_once $filename;
580
581
        $property   = new \ReflectionProperty($metadata->name, 'centroCustos');
582
        $docComment = $property->getDocComment();
583
584
        //joinColumns
585
        $this->assertContains('@JoinColumn(name="idorcamento", referencedColumnName="idorcamento"),', $docComment);
586
        $this->assertContains('@JoinColumn(name="idunidade", referencedColumnName="idunidade")', $docComment);
587
        //inverseJoinColumns
588
        $this->assertContains('@JoinColumn(name="idcentrocusto", referencedColumnName="idcentrocusto"),', $docComment);
589
        $this->assertContains('@JoinColumn(name="idpais", referencedColumnName="idpais")', $docComment);
590
591
    }
592
593
     /**
594
     * @group DDC-2172
595
     */
596
    public function testGetInheritanceTypeString()
597
    {
598
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadataInfo');
599
        $method     = new \ReflectionMethod($this->_generator, 'getInheritanceTypeString');
600
        $constants  = $reflection->getConstants();
601
        $pattern    = '/^INHERITANCE_TYPE_/';
602
603
        $method->setAccessible(true);
604
605
        foreach ($constants as $name => $value) {
606
            if( ! preg_match($pattern, $name)) {
607
                continue;
608
            }
609
610
            $expected = preg_replace($pattern, '', $name);
611
            $actual   = $method->invoke($this->_generator, $value);
612
613
            $this->assertEquals($expected, $actual);
614
        }
615
616
        $this->expectException(\InvalidArgumentException::class);
617
        $this->expectExceptionMessage('Invalid provided InheritanceType: INVALID');
618
619
        $method->invoke($this->_generator, 'INVALID');
620
    }
621
622
    /**
623
    * @group DDC-2172
624
    */
625
    public function testGetChangeTrackingPolicyString()
626
    {
627
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadata');
628
        $method     = new \ReflectionMethod($this->_generator, 'getChangeTrackingPolicyString');
629
        $constants  = $reflection->getConstants();
630
        $pattern    = '/^CHANGETRACKING_/';
631
632
        $method->setAccessible(true);
633
634
        foreach ($constants as $name => $value) {
635
            if( ! preg_match($pattern, $name)) {
636
                continue;
637
            }
638
639
            $expected = preg_replace($pattern, '', $name);
640
            $actual   = $method->invoke($this->_generator, $value);
641
642
            $this->assertEquals($expected, $actual);
643
        }
644
645
        $this->expectException(\InvalidArgumentException::class);
646
        $this->expectExceptionMessage('Invalid provided ChangeTrackingPolicy: INVALID');
647
648
        $method->invoke($this->_generator, 'INVALID');
649
    }
650
651
    /**
652
     * @group DDC-2172
653
     */
654
    public function testGetIdGeneratorTypeString()
655
    {
656
        $reflection = new \ReflectionClass('\Doctrine\ORM\Mapping\ClassMetadataInfo');
657
        $method     = new \ReflectionMethod($this->_generator, 'getIdGeneratorTypeString');
658
        $constants  = $reflection->getConstants();
659
        $pattern    = '/^GENERATOR_TYPE_/';
660
661
        $method->setAccessible(true);
662
663
        foreach ($constants as $name => $value) {
664
            if( ! preg_match($pattern, $name)) {
665
                continue;
666
            }
667
668
            $expected = preg_replace($pattern, '', $name);
669
            $actual   = $method->invoke($this->_generator, $value);
670
671
            $this->assertEquals($expected, $actual);
672
        }
673
674
        $this->expectException(\InvalidArgumentException::class);
675
        $this->expectExceptionMessage('Invalid provided IdGeneratorType: INVALID');
676
677
        $method->invoke($this->_generator, 'INVALID');
678
    }
679
680
    /**
681
     * @dataProvider getEntityTypeAliasDataProvider
682
     *
683
     * @group DDC-1694
684
     */
685
    public function testEntityTypeAlias(array $field)
686
    {
687
        $metadata   = $this->generateEntityTypeFixture($field);
688
        $path       = $this->_tmpDir . '/'. $this->_namespace . '/EntityType.php';
689
690
        $this->assertFileExists($path);
691
        require_once $path;
692
693
        $entity     = new $metadata->name;
694
        $reflClass  = new \ReflectionClass($metadata->name);
695
696
        $type   = $field['phpType'];
697
        $name   = $field['fieldName'];
698
        $value  = $field['value'];
699
        $getter = "get" . ucfirst($name);
700
        $setter = "set" . ucfirst($name);
701
702
        $this->assertPhpDocVarType($type, $reflClass->getProperty($name));
703
        $this->assertPhpDocParamType($type, $reflClass->getMethod($setter));
704
        $this->assertPhpDocReturnType($type, $reflClass->getMethod($getter));
705
706
        $this->assertSame($entity, $entity->{$setter}($value));
707
        $this->assertEquals($value, $entity->{$getter}());
708
    }
709
710
    /**
711
     * @group DDC-2372
712
     */
713
    public function testTraitPropertiesAndMethodsAreNotDuplicated()
714
    {
715
        $cmf = new ClassMetadataFactory();
716
        $em = $this->_getTestEntityManager();
717
        $cmf->setEntityManager($em);
718
719
        $user = new DDC2372User();
720
        $metadata = $cmf->getMetadataFor(get_class($user));
721
        $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...
722
        $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...
723
724
        $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...
725
726
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/DDC2372User.php");
727
        require $this->_tmpDir . "/" . $this->_namespace . "/DDC2372User.php";
728
729
        $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...
730
731
        $this->assertSame($reflClass->hasProperty('address'), false);
732
        $this->assertSame($reflClass->hasMethod('setAddress'), false);
733
        $this->assertSame($reflClass->hasMethod('getAddress'), false);
734
    }
735
736
    /**
737
     * @group DDC-2372
738
     */
739
    public function testTraitPropertiesAndMethodsAreNotDuplicatedInChildClasses()
740
    {
741
        $cmf = new ClassMetadataFactory();
742
        $em = $this->_getTestEntityManager();
743
        $cmf->setEntityManager($em);
744
745
        $user = new DDC2372Admin();
746
        $metadata = $cmf->getMetadataFor(get_class($user));
747
        $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...
748
        $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...
749
750
        $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...
751
752
        $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/DDC2372Admin.php");
753
        require $this->_tmpDir . "/" . $this->_namespace . "/DDC2372Admin.php";
754
755
        $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...
756
757
        $this->assertSame($reflClass->hasProperty('address'), false);
758
        $this->assertSame($reflClass->hasMethod('setAddress'), false);
759
        $this->assertSame($reflClass->hasMethod('getAddress'), false);
760
    }
761
762
    /**
763
     * @group DDC-1590
764
     */
765
    public function testMethodsAndPropertiesAreNotDuplicatedInChildClasses()
766
    {
767
        $cmf    = new ClassMetadataFactory();
768
        $em     = $this->_getTestEntityManager();
769
770
        $cmf->setEntityManager($em);
771
772
        $ns     = $this->_namespace;
773
        $nsdir  = $this->_tmpDir . '/' . $ns;
774
775
        $content = str_replace(
776
            'namespace Doctrine\Tests\Models\DDC1590',
777
            'namespace ' . $ns,
778
            file_get_contents(__DIR__ . '/../../Models/DDC1590/DDC1590User.php')
779
        );
780
781
        $fname = $nsdir . "/DDC1590User.php";
782
        file_put_contents($fname, $content);
783
        require $fname;
784
785
786
        $metadata = $cmf->getMetadataFor($ns . '\DDC1590User');
787
        $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...
788
789
        // class DDC1590User extends DDC1590Entity { ... }
790
        $source = file_get_contents($fname);
791
792
        // class _DDC1590User extends DDC1590Entity { ... }
793
        $source2    = str_replace('class DDC1590User', 'class _DDC1590User', $source);
794
        $fname2     = $nsdir . "/_DDC1590User.php";
795
        file_put_contents($fname2, $source2);
796
        require $fname2;
797
798
        // class __DDC1590User { ... }
799
        $source3    = str_replace('class DDC1590User extends DDC1590Entity', 'class __DDC1590User', $source);
800
        $fname3     = $nsdir . "/__DDC1590User.php";
801
        file_put_contents($fname3, $source3);
802
        require $fname3;
803
804
805
        // class _DDC1590User extends DDC1590Entity { ... }
806
        $rc2 = new \ReflectionClass($ns.'\_DDC1590User');
807
808
        $this->assertTrue($rc2->hasProperty('name'));
809
        $this->assertTrue($rc2->hasProperty('id'));
810
        $this->assertTrue($rc2->hasProperty('created_at'));
811
812
        $this->assertTrue($rc2->hasMethod('getName'));
813
        $this->assertTrue($rc2->hasMethod('setName'));
814
        $this->assertTrue($rc2->hasMethod('getId'));
815
        $this->assertFalse($rc2->hasMethod('setId'));
816
        $this->assertTrue($rc2->hasMethod('getCreatedAt'));
817
        $this->assertTrue($rc2->hasMethod('setCreatedAt'));
818
819
820
        // class __DDC1590User { ... }
821
        $rc3 = new \ReflectionClass($ns.'\__DDC1590User');
822
823
        $this->assertTrue($rc3->hasProperty('name'));
824
        $this->assertFalse($rc3->hasProperty('id'));
825
        $this->assertFalse($rc3->hasProperty('created_at'));
826
827
        $this->assertTrue($rc3->hasMethod('getName'));
828
        $this->assertTrue($rc3->hasMethod('setName'));
829
        $this->assertFalse($rc3->hasMethod('getId'));
830
        $this->assertFalse($rc3->hasMethod('setId'));
831
        $this->assertFalse($rc3->hasMethod('getCreatedAt'));
832
        $this->assertFalse($rc3->hasMethod('setCreatedAt'));
833
    }
834
835
    /**
836
     * @group DDC-3304
837
     */
838
    public function testGeneratedMutableEmbeddablesClass()
839
    {
840
        $embeddedMetadata = $this->generateTestEmbeddableFixture();
841
        $metadata = $this->generateIsbnEmbeddableFixture(array('test' => $embeddedMetadata));
842
843
        $isbn = $this->newInstance($metadata);
844
845
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
846
        $this->assertFalse(method_exists($metadata->name, '__construct'), "EntityGeneratorIsbn::__construct present.");
847
        $this->assertTrue(method_exists($metadata->name, 'getPrefix'), "EntityGeneratorIsbn::getPrefix() missing.");
848
        $this->assertTrue(method_exists($metadata->name, 'setPrefix'), "EntityGeneratorIsbn::setPrefix() missing.");
849
        $this->assertTrue(method_exists($metadata->name, 'getGroupNumber'), "EntityGeneratorIsbn::getGroupNumber() missing.");
850
        $this->assertTrue(method_exists($metadata->name, 'setGroupNumber'), "EntityGeneratorIsbn::setGroupNumber() missing.");
851
        $this->assertTrue(method_exists($metadata->name, 'getPublisherNumber'), "EntityGeneratorIsbn::getPublisherNumber() missing.");
852
        $this->assertTrue(method_exists($metadata->name, 'setPublisherNumber'), "EntityGeneratorIsbn::setPublisherNumber() missing.");
853
        $this->assertTrue(method_exists($metadata->name, 'getTitleNumber'), "EntityGeneratorIsbn::getTitleNumber() missing.");
854
        $this->assertTrue(method_exists($metadata->name, 'setTitleNumber'), "EntityGeneratorIsbn::setTitleNumber() missing.");
855
        $this->assertTrue(method_exists($metadata->name, 'getCheckDigit'), "EntityGeneratorIsbn::getCheckDigit() missing.");
856
        $this->assertTrue(method_exists($metadata->name, 'setCheckDigit'), "EntityGeneratorIsbn::setCheckDigit() missing.");
857
        $this->assertTrue(method_exists($metadata->name, 'getTest'), "EntityGeneratorIsbn::getTest() missing.");
858
        $this->assertTrue(method_exists($metadata->name, 'setTest'), "EntityGeneratorIsbn::setTest() missing.");
859
860
        $isbn->setPrefix(978);
861
        $this->assertSame(978, $isbn->getPrefix());
862
863
        $this->newInstance($embeddedMetadata);
864
        $test = new $embeddedMetadata->name();
865
866
        $isbn->setTest($test);
867
        $this->assertSame($test, $isbn->getTest());
868
869
        $reflMethod = new \ReflectionMethod($metadata->name, 'setTest');
870
        $reflParameters = $reflMethod->getParameters();
871
        $this->assertEquals($embeddedMetadata->name, $reflParameters[0]->getClass()->name);
872
    }
873
874
    /**
875
     * @group DDC-3304
876
     */
877
    public function testGeneratedImmutableEmbeddablesClass()
878
    {
879
        $this->_generator->setEmbeddablesImmutable(true);
880
        $embeddedMetadata = $this->generateTestEmbeddableFixture();
881
        $metadata = $this->generateIsbnEmbeddableFixture(array('test' => $embeddedMetadata));
882
883
        $this->loadEntityClass($embeddedMetadata);
884
        $this->loadEntityClass($metadata);
885
886
        $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
887
        $this->assertTrue(method_exists($metadata->name, '__construct'), "EntityGeneratorIsbn::__construct missing.");
888
        $this->assertTrue(method_exists($metadata->name, 'getPrefix'), "EntityGeneratorIsbn::getPrefix() missing.");
889
        $this->assertFalse(method_exists($metadata->name, 'setPrefix'), "EntityGeneratorIsbn::setPrefix() present.");
890
        $this->assertTrue(method_exists($metadata->name, 'getGroupNumber'), "EntityGeneratorIsbn::getGroupNumber() missing.");
891
        $this->assertFalse(method_exists($metadata->name, 'setGroupNumber'), "EntityGeneratorIsbn::setGroupNumber() present.");
892
        $this->assertTrue(method_exists($metadata->name, 'getPublisherNumber'), "EntityGeneratorIsbn::getPublisherNumber() missing.");
893
        $this->assertFalse(method_exists($metadata->name, 'setPublisherNumber'), "EntityGeneratorIsbn::setPublisherNumber() present.");
894
        $this->assertTrue(method_exists($metadata->name, 'getTitleNumber'), "EntityGeneratorIsbn::getTitleNumber() missing.");
895
        $this->assertFalse(method_exists($metadata->name, 'setTitleNumber'), "EntityGeneratorIsbn::setTitleNumber() present.");
896
        $this->assertTrue(method_exists($metadata->name, 'getCheckDigit'), "EntityGeneratorIsbn::getCheckDigit() missing.");
897
        $this->assertFalse(method_exists($metadata->name, 'setCheckDigit'), "EntityGeneratorIsbn::setCheckDigit() present.");
898
        $this->assertTrue(method_exists($metadata->name, 'getTest'), "EntityGeneratorIsbn::getTest() missing.");
899
        $this->assertFalse(method_exists($metadata->name, 'setTest'), "EntityGeneratorIsbn::setTest() present.");
900
901
        $test = new $embeddedMetadata->name(1, new \DateTime());
902
        $isbn = new $metadata->name($test, 978, 3, 12, 732320, 83);
903
904
        $reflMethod = new \ReflectionMethod($isbn, '__construct');
905
        $reflParameters = $reflMethod->getParameters();
906
907
        $this->assertCount(6, $reflParameters);
908
909
        $this->assertSame($embeddedMetadata->name, $reflParameters[0]->getClass()->name);
910
        $this->assertSame('test', $reflParameters[0]->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflParameters[0]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
911
        $this->assertFalse($reflParameters[0]->isOptional());
912
913
        $this->assertSame('prefix', $reflParameters[1]->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflParameters[1]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
914
        $this->assertFalse($reflParameters[1]->isOptional());
915
916
        $this->assertSame('groupNumber', $reflParameters[2]->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflParameters[2]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
917
        $this->assertFalse($reflParameters[2]->isOptional());
918
919
        $this->assertSame('publisherNumber', $reflParameters[3]->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflParameters[3]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
920
        $this->assertFalse($reflParameters[3]->isOptional());
921
922
        $this->assertSame('titleNumber', $reflParameters[4]->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflParameters[4]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
923
        $this->assertFalse($reflParameters[4]->isOptional());
924
925
        $this->assertSame('checkDigit', $reflParameters[5]->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflParameters[5]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
926
        $this->assertFalse($reflParameters[5]->isOptional());
927
928
        $reflMethod = new \ReflectionMethod($test, '__construct');
929
        $reflParameters = $reflMethod->getParameters();
930
931
        $this->assertCount(4, $reflParameters);
932
933
        $this->assertSame('field1', $reflParameters[0]->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflParameters[0]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
934
        $this->assertFalse($reflParameters[0]->isOptional());
935
936
        $this->assertSame('DateTime', $reflParameters[1]->getClass()->name);
937
        $this->assertSame('field3', $reflParameters[1]->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflParameters[1]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
938
        $this->assertFalse($reflParameters[1]->isOptional());
939
940
        $this->assertSame('field2', $reflParameters[2]->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflParameters[2]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
941
        $this->assertTrue($reflParameters[2]->isOptional());
942
943
        $this->assertSame('DateTime', $reflParameters[3]->getClass()->name);
944
        $this->assertSame('field4', $reflParameters[3]->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflParameters[3]->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
945
        $this->assertTrue($reflParameters[3]->isOptional());
946
    }
947
948
    public function testRegenerateEntityClass()
949
    {
950
        $metadata = $this->generateBookEntityFixture();
951
        $this->loadEntityClass($metadata);
952
953
        $className = basename(str_replace('\\', '/', $metadata->name));
954
        $path = $this->_tmpDir . '/' . $this->_namespace . '/' . $className . '.php';
955
        $classTest = file_get_contents($path);
956
957
        $this->_generator->setRegenerateEntityIfExists(true);
958
        $this->_generator->setBackupExisting(false);
959
960
        $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
961
        $classNew = file_get_contents($path);
962
963
        $this->assertSame($classTest,$classNew);
964
    }
965
966
    /**
967
     * @return array
968
     */
969
    public function getEntityTypeAliasDataProvider()
970
    {
971
        return array(
972
            array(array(
973
                'fieldName' => 'datetimetz',
974
                'phpType' => '\\DateTime',
975
                'dbType' => 'datetimetz',
976
                'value' => new \DateTime
977
            )),
978
            array(array(
979
                'fieldName' => 'datetime',
980
                'phpType' => '\\DateTime',
981
                'dbType' => 'datetime',
982
                'value' => new \DateTime
983
            )),
984
            array(array(
985
                'fieldName' => 'date',
986
                'phpType' => '\\DateTime',
987
                'dbType' => 'date',
988
                'value' => new \DateTime
989
            )),
990
            array(array(
991
                'fieldName' => 'time',
992
                'phpType' => '\DateTime',
993
                'dbType' => 'time',
994
                'value' => new \DateTime
995
            )),
996
            array(array(
997
                'fieldName' => 'object',
998
                'phpType' => '\stdClass',
999
                'dbType' => 'object',
1000
                'value' => new \stdClass()
1001
            )),
1002
            array(array(
1003
                'fieldName' => 'bigint',
1004
                'phpType' => 'int',
1005
                'dbType' => 'bigint',
1006
                'value' => 11
1007
            )),
1008
            array(array(
1009
                'fieldName' => 'smallint',
1010
                'phpType' => 'int',
1011
                'dbType' => 'smallint',
1012
                'value' => 22
1013
            )),
1014
            array(array(
1015
                'fieldName' => 'text',
1016
                'phpType' => 'string',
1017
                'dbType' => 'text',
1018
                'value' => 'text'
1019
            )),
1020
            array(array(
1021
                'fieldName' => 'blob',
1022
                'phpType' => 'string',
1023
                'dbType' => 'blob',
1024
                'value' => 'blob'
1025
            )),
1026
            array(array(
1027
                'fieldName' => 'decimal',
1028
                'phpType' => 'string',
1029
                'dbType' => 'decimal',
1030
                'value' => '12.34'
1031
            ),
1032
        ));
1033
    }
1034
1035
    public function getParseTokensInEntityFileData()
1036
    {
1037
        return array(
1038
            array(
1039
                '<?php namespace Foo\Bar; class Baz {}',
1040
                array('Foo\Bar\Baz'),
1041
            ),
1042
            array(
1043
                '<?php namespace Foo\Bar; use Foo; class Baz {}',
1044
                array('Foo\Bar\Baz'),
1045
            ),
1046
            array(
1047
                '<?php namespace /*Comment*/ Foo\Bar; /** Foo */class /* Comment */ Baz {}',
1048
                array('Foo\Bar\Baz'),
1049
            ),
1050
            array(
1051
                '
1052
<?php namespace
1053
/*Comment*/
1054
Foo\Bar
1055
;
1056
1057
/** Foo */
1058
class
1059
/* Comment */
1060
 Baz {}
1061
     ',
1062
                array('Foo\Bar\Baz'),
1063
            ),
1064
            array(
1065
                '
1066
<?php namespace Foo\Bar; class Baz {
1067
    public static function someMethod(){
1068
        return self::class;
1069
    }
1070
}
1071
',
1072
                array('Foo\Bar\Baz'),
1073
            ),
1074
        );
1075
    }
1076
1077
    /**
1078
     * @param string $type
1079
     * @param \ReflectionProperty $property
1080
     */
1081
    private function assertPhpDocVarType($type, \ReflectionProperty $property)
1082
    {
1083
        $this->assertEquals(1, preg_match('/@var\s+([^\s]+)/',$property->getDocComment(), $matches));
1084
        $this->assertEquals($type, $matches[1]);
1085
    }
1086
1087
    /**
1088
     * @param string $type
1089
     * @param \ReflectionProperty $method
1090
     */
1091
    private function assertPhpDocReturnType($type, \ReflectionMethod $method)
1092
    {
1093
        $this->assertEquals(1, preg_match('/@return\s+([^\s]+)/', $method->getDocComment(), $matches));
1094
        $this->assertEquals($type, $matches[1]);
1095
    }
1096
1097
    /**
1098
     * @param string $type
1099
     * @param \ReflectionProperty $method
1100
     */
1101
    private function assertPhpDocParamType($type, \ReflectionMethod $method)
1102
    {
1103
        $this->assertEquals(1, preg_match('/@param\s+([^\s]+)/', $method->getDocComment(), $matches));
1104
        $this->assertEquals($type, $matches[1]);
1105
    }
1106
}
1107
1108
class EntityGeneratorAuthor {}
1109
class EntityGeneratorComment {}
1110