Rajout de doctrine/orm
[zf2.biz/galerie.git] / vendor / doctrine / orm / tests / Doctrine / Tests / ORM / Tools / EntityGeneratorTest.php
1 <?php
2
3 namespace Doctrine\Tests\ORM\Tools;
4
5 use Doctrine\ORM\Tools\SchemaTool,
6     Doctrine\ORM\Tools\EntityGenerator,
7     Doctrine\ORM\Tools\Export\ClassMetadataExporter,
8     Doctrine\ORM\Mapping\ClassMetadataInfo;
9
10 require_once __DIR__ . '/../../TestInit.php';
11
12 class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
13 {
14
15     /**
16      * @var EntityGenerator
17      */
18     private $_generator;
19     private $_tmpDir;
20     private $_namespace;
21
22     public function setUp()
23     {
24         $this->_namespace = uniqid("doctrine_");
25         $this->_tmpDir = \sys_get_temp_dir();
26         \mkdir($this->_tmpDir . \DIRECTORY_SEPARATOR . $this->_namespace);
27         $this->_generator = new EntityGenerator();
28         $this->_generator->setAnnotationPrefix("");
29         $this->_generator->setGenerateAnnotations(true);
30         $this->_generator->setGenerateStubMethods(true);
31         $this->_generator->setRegenerateEntityIfExists(false);
32         $this->_generator->setUpdateEntityIfExists(true);
33         $this->_generator->setFieldVisibility(EntityGenerator::FIELD_VISIBLE_PROTECTED);
34     }
35
36     public function tearDown()
37     {
38         $ri = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->_tmpDir . '/' . $this->_namespace));
39         foreach ($ri AS $file) {
40             /* @var $file \SplFileInfo */
41             if ($file->isFile()) {
42                 \unlink($file->getPathname());
43             }
44         }
45         rmdir($this->_tmpDir . '/' . $this->_namespace);
46     }
47
48     public function generateBookEntityFixture()
49     {
50         $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorBook');
51         $metadata->namespace = $this->_namespace;
52         $metadata->customRepositoryClassName = $this->_namespace  . '\EntityGeneratorBookRepository';
53
54         $metadata->table['name'] = 'book';
55         $metadata->table['uniqueConstraints']['name_uniq'] = array('columns' => array('name'));
56         $metadata->table['indexes']['status_idx'] = array('columns' => array('status'));
57         $metadata->mapField(array('fieldName' => 'name', 'type' => 'string'));
58         $metadata->mapField(array('fieldName' => 'status', 'type' => 'string', 'default' => 'published'));
59         $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
60         $metadata->mapOneToOne(array('fieldName' => 'author', 'targetEntity' => 'Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', 'mappedBy' => 'book'));
61         $joinColumns = array(
62             array('name' => 'author_id', 'referencedColumnName' => 'id')
63         );
64         $metadata->mapManyToMany(array(
65             'fieldName' => 'comments',
66             'targetEntity' => 'Doctrine\Tests\ORM\Tools\EntityGeneratorComment',
67             'joinTable' => array(
68                 'name' => 'book_comment',
69                 'joinColumns' => array(array('name' => 'book_id', 'referencedColumnName' => 'id')),
70                 'inverseJoinColumns' => array(array('name' => 'comment_id', 'referencedColumnName' => 'id')),
71             ),
72         ));
73         $metadata->addLifecycleCallback('loading', 'postLoad');
74         $metadata->addLifecycleCallback('willBeRemoved', 'preRemove');
75         $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
76
77         $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
78
79         return $metadata;
80     }
81
82     private function generateEntityTypeFixture(array $field)
83     {
84         $metadata = new ClassMetadataInfo($this->_namespace . '\EntityType');
85         $metadata->namespace = $this->_namespace;
86
87         $metadata->table['name'] = 'entity_type';
88         $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
89         $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
90
91         $name  = $field['fieldName'];
92         $type  = $field['dbType'];
93         $metadata->mapField(array('fieldName' => $name, 'type' => $type));
94
95         $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
96
97         return $metadata;
98     }
99
100     /**
101      * @param  ClassMetadataInfo $metadata
102      * @return EntityGeneratorBook
103      */
104     public function newInstance($metadata)
105     {
106         $path = $this->_tmpDir . '/'. $this->_namespace . '/EntityGeneratorBook.php';
107         $this->assertFileExists($path);
108         require_once $path;
109
110         return new $metadata->name;
111     }
112
113     public function testGeneratedEntityClass()
114     {
115         $metadata = $this->generateBookEntityFixture();
116
117         $book = $this->newInstance($metadata);
118         $this->assertTrue(class_exists($metadata->name), "Class does not exist.");
119         $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', '__construct'), "EntityGeneratorBook::__construct() missing.");
120         $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getId'), "EntityGeneratorBook::getId() missing.");
121         $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setName'), "EntityGeneratorBook::setName() missing.");
122         $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getName'), "EntityGeneratorBook::getName() missing.");
123         $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setAuthor'), "EntityGeneratorBook::setAuthor() missing.");
124         $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getAuthor'), "EntityGeneratorBook::getAuthor() missing.");
125         $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getComments'), "EntityGeneratorBook::getComments() missing.");
126         $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'addComment'), "EntityGeneratorBook::addComment() missing.");
127         $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'removeComment'), "EntityGeneratorBook::removeComment() missing.");
128
129         $this->assertEquals('published', $book->getStatus());
130
131         $book->setName('Jonathan H. Wage');
132         $this->assertEquals('Jonathan H. Wage', $book->getName());
133
134         $author = new EntityGeneratorAuthor();
135         $book->setAuthor($author);
136         $this->assertEquals($author, $book->getAuthor());
137
138         $comment = new EntityGeneratorComment();
139         $book->addComment($comment);
140         $this->assertInstanceOf('Doctrine\Common\Collections\ArrayCollection', $book->getComments());
141         $this->assertEquals(new \Doctrine\Common\Collections\ArrayCollection(array($comment)), $book->getComments());
142         $book->removeComment($comment);
143         $this->assertEquals(new \Doctrine\Common\Collections\ArrayCollection(array()), $book->getComments());
144     }
145
146     public function testEntityUpdatingWorks()
147     {
148         $metadata = $this->generateBookEntityFixture();
149         $metadata->mapField(array('fieldName' => 'test', 'type' => 'string'));
150
151         $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
152
153         $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
154
155         $book = $this->newInstance($metadata);
156         $reflClass = new \ReflectionClass($metadata->name);
157
158         $this->assertTrue($reflClass->hasProperty('name'), "Regenerating keeps property 'name'.");
159         $this->assertTrue($reflClass->hasProperty('status'), "Regenerating keeps property 'status'.");
160         $this->assertTrue($reflClass->hasProperty('id'), "Regenerating keeps property 'id'.");
161
162         $this->assertTrue($reflClass->hasProperty('test'), "Check for property test failed.");
163         $this->assertTrue($reflClass->getProperty('test')->isProtected(), "Check for protected property test failed.");
164         $this->assertTrue($reflClass->hasMethod('getTest'), "Check for method 'getTest' failed.");
165         $this->assertTrue($reflClass->getMethod('getTest')->isPublic(), "Check for public visibility of method 'getTest' failed.");
166         $this->assertTrue($reflClass->hasMethod('setTest'), "Check for method 'getTest' failed.");
167         $this->assertTrue($reflClass->getMethod('getTest')->isPublic(), "Check for public visibility of method 'getTest' failed.");
168     }
169
170     public function testEntityExtendsStdClass()
171     {
172         $this->_generator->setClassToExtend('stdClass');
173         $metadata = $this->generateBookEntityFixture();
174
175         $book = $this->newInstance($metadata);
176         $this->assertInstanceOf('stdClass', $book);
177     }
178
179     public function testLifecycleCallbacks()
180     {
181         $metadata = $this->generateBookEntityFixture();
182
183         $book = $this->newInstance($metadata);
184         $reflClass = new \ReflectionClass($metadata->name);
185
186         $this->assertTrue($reflClass->hasMethod('loading'), "Check for postLoad lifecycle callback.");
187         $this->assertTrue($reflClass->hasMethod('willBeRemoved'), "Check for preRemove lifecycle callback.");
188     }
189
190     public function testLoadMetadata()
191     {
192         $metadata = $this->generateBookEntityFixture();
193
194         $book = $this->newInstance($metadata);
195
196         $cm = new \Doctrine\ORM\Mapping\ClassMetadata($metadata->name);
197         $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
198
199         $driver = $this->createAnnotationDriver();
200         $driver->loadMetadataForClass($cm->name, $cm);
201
202         $this->assertEquals($cm->columnNames, $metadata->columnNames);
203         $this->assertEquals($cm->getTableName(), $metadata->getTableName());
204         $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
205         $this->assertEquals($cm->identifier, $metadata->identifier);
206         $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
207         $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
208     }
209
210     public function testLoadPrefixedMetadata()
211     {
212         $this->_generator->setAnnotationPrefix('ORM\\');
213         $metadata = $this->generateBookEntityFixture();
214
215         $reader = new \Doctrine\Common\Annotations\AnnotationReader();
216         $driver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader, array());
217
218         $book = $this->newInstance($metadata);
219
220         $cm = new \Doctrine\ORM\Mapping\ClassMetadata($metadata->name);
221         $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
222
223         $driver->loadMetadataForClass($cm->name, $cm);
224
225         $this->assertEquals($cm->columnNames, $metadata->columnNames);
226         $this->assertEquals($cm->getTableName(), $metadata->getTableName());
227         $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks);
228         $this->assertEquals($cm->identifier, $metadata->identifier);
229         $this->assertEquals($cm->idGenerator, $metadata->idGenerator);
230         $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
231     }
232
233     /**
234      * @dataProvider getParseTokensInEntityFileData
235      */
236     public function testParseTokensInEntityFile($php, $classes)
237     {
238         $r = new \ReflectionObject($this->_generator);
239         $m = $r->getMethod('parseTokensInEntityFile');
240         $m->setAccessible(true);
241
242         $p = $r->getProperty('staticReflection');
243         $p->setAccessible(true);
244
245         $ret = $m->invoke($this->_generator, $php);
246         $this->assertEquals($classes, array_keys($p->getValue($this->_generator)));
247     }
248
249     /**
250      * @group DDC-1784
251      */
252     public function testGenerateEntityWithSequenceGenerator()
253     {
254         $metadata               = new ClassMetadataInfo($this->_namespace . '\DDC1784Entity');
255         $metadata->namespace    = $this->_namespace;
256         $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
257         $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE);
258         $metadata->setSequenceGeneratorDefinition(array(
259             'sequenceName'      => 'DDC1784_ID_SEQ',
260             'allocationSize'    => 1,
261             'initialValue'      => 2
262         ));
263         $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
264
265         $filename = $this->_tmpDir . DIRECTORY_SEPARATOR
266                   . $this->_namespace . DIRECTORY_SEPARATOR . 'DDC1784Entity.php';
267         
268         $this->assertFileExists($filename);
269         require_once $filename;
270
271
272         $reflection = new \ReflectionProperty($metadata->name, 'id');
273         $docComment = $reflection->getDocComment();
274
275         $this->assertContains('@Id', $docComment);
276         $this->assertContains('@Column(name="id", type="integer")', $docComment);
277         $this->assertContains('@GeneratedValue(strategy="SEQUENCE")', $docComment);
278         $this->assertContains('@SequenceGenerator(sequenceName="DDC1784_ID_SEQ", allocationSize=1, initialValue=2)', $docComment);
279     }
280
281     /**
282      * @dataProvider getEntityTypeAliasDataProvider
283      *
284      * @group DDC-1694
285      */
286     public function testEntityTypeAlias(array $field)
287     {
288         $metadata   = $this->generateEntityTypeFixture($field);
289         $path       = $this->_tmpDir . '/'. $this->_namespace . '/EntityType.php';
290
291         $this->assertFileExists($path);
292         require_once $path;
293
294         $entity     = new $metadata->name;
295         $reflClass  = new \ReflectionClass($metadata->name);
296         
297         $type   = $field['phpType'];
298         $name   = $field['fieldName'];
299         $value  = $field['value'];
300         $getter = "get" . ucfirst($name);
301         $setter = "set" . ucfirst($name);
302
303         $this->assertPhpDocVarType($type, $reflClass->getProperty($name));
304         $this->assertPhpDocParamType($type, $reflClass->getMethod($setter));
305         $this->assertPhpDocReturnType($type, $reflClass->getMethod($getter));
306
307         $this->assertSame($entity, $entity->{$setter}($value));
308         $this->assertEquals($value, $entity->{$getter}());
309     }
310
311     /**
312      * @return array
313      */
314     public function getEntityTypeAliasDataProvider()
315     {
316         return array(
317             array(array(
318                 'fieldName' => 'datetimetz',
319                 'phpType' => '\\DateTime',
320                 'dbType' => 'datetimetz',
321                 'value' => new \DateTime
322             )),
323             array(array(
324                 'fieldName' => 'datetime',
325                 'phpType' => '\\DateTime',
326                 'dbType' => 'datetime',
327                 'value' => new \DateTime
328             )),
329             array(array(
330                 'fieldName' => 'date', 
331                 'phpType' => '\\DateTime',
332                 'dbType' => 'date',
333                 'value' => new \DateTime
334             )),
335             array(array(
336                 'fieldName' => 'time', 
337                 'phpType' => '\DateTime',
338                 'dbType' => 'time',
339                 'value' => new \DateTime
340             )),
341             array(array(
342                 'fieldName' => 'object', 
343                 'phpType' => '\stdClass',
344                 'dbType' => 'object',
345                 'value' => new \stdClass()
346             )),
347             array(array(
348                 'fieldName' => 'bigint', 
349                 'phpType' => 'integer',
350                 'dbType' => 'bigint',
351                 'value' => 11
352             )),
353             array(array(
354                 'fieldName' => 'smallint', 
355                 'phpType' => 'integer',
356                 'dbType' => 'smallint',
357                 'value' => 22
358             )),
359             array(array(
360                 'fieldName' => 'text', 
361                 'phpType' => 'string',
362                 'dbType' => 'text',
363                 'value' => 'text'
364             )),
365             array(array(
366                 'fieldName' => 'blob', 
367                 'phpType' => 'string',
368                 'dbType' => 'blob',
369                 'value' => 'blob'
370             )),
371             array(array(
372                 'fieldName' => 'decimal',
373                 'phpType' => 'float',
374                 'dbType' => 'decimal',
375                 'value' => 33.33
376             ),
377         ));
378     }
379
380     public function getParseTokensInEntityFileData()
381     {
382         return array(
383             array(
384                 '<?php namespace Foo\Bar; class Baz {}',
385                 array('Foo\Bar\Baz'),
386             ),
387             array(
388                 '<?php namespace Foo\Bar; use Foo; class Baz {}',
389                 array('Foo\Bar\Baz'),
390             ),
391             array(
392                 '<?php namespace /*Comment*/ Foo\Bar; /** Foo */class /* Comment */ Baz {}',
393                 array('Foo\Bar\Baz'),
394             ),
395             array(
396                 '
397 <?php namespace
398 /*Comment*/
399 Foo\Bar
400 ;
401
402 /** Foo */
403 class
404 /* Comment */
405  Baz {}
406      ',
407                 array('Foo\Bar\Baz'),
408             ),
409         );
410     }
411
412     /**
413      * @param string $type
414      * @param \ReflectionProperty $property
415      */
416     private function assertPhpDocVarType($type, \ReflectionProperty $property)
417     {
418         $this->assertEquals(1, preg_match('/@var\s+([^\s]+)/',$property->getDocComment(), $matches));
419         $this->assertEquals($type, $matches[1]);
420     }
421
422     /**
423      * @param string $type
424      * @param \ReflectionProperty $method
425      */
426     private function assertPhpDocReturnType($type, \ReflectionMethod $method)
427     {
428         $this->assertEquals(1, preg_match('/@return\s+([^\s]+)/', $method->getDocComment(), $matches));
429         $this->assertEquals($type, $matches[1]);
430     }
431
432     /**
433      * @param string $type
434      * @param \ReflectionProperty $method
435      */
436     private function assertPhpDocParamType($type, \ReflectionMethod $method)
437     {
438         $this->assertEquals(1, preg_match('/@param\s+([^\s]+)/', $method->getDocComment(), $matches));
439         $this->assertEquals($type, $matches[1]);
440     }
441 }
442
443 class EntityGeneratorAuthor {}
444 class EntityGeneratorComment {}