3 namespace Doctrine\Tests\ORM\Tools;
5 use Doctrine\ORM\Tools\SchemaTool,
6 Doctrine\ORM\Tools\EntityGenerator,
7 Doctrine\ORM\Tools\Export\ClassMetadataExporter,
8 Doctrine\ORM\Mapping\ClassMetadataInfo;
10 require_once __DIR__ . '/../../TestInit.php';
12 class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
16 * @var EntityGenerator
22 public function setUp()
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);
36 public function tearDown()
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());
45 rmdir($this->_tmpDir . '/' . $this->_namespace);
48 public function generateBookEntityFixture()
50 $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorBook');
51 $metadata->namespace = $this->_namespace;
52 $metadata->customRepositoryClassName = $this->_namespace . '\EntityGeneratorBookRepository';
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'));
62 array('name' => 'author_id', 'referencedColumnName' => 'id')
64 $metadata->mapManyToMany(array(
65 'fieldName' => 'comments',
66 'targetEntity' => 'Doctrine\Tests\ORM\Tools\EntityGeneratorComment',
68 'name' => 'book_comment',
69 'joinColumns' => array(array('name' => 'book_id', 'referencedColumnName' => 'id')),
70 'inverseJoinColumns' => array(array('name' => 'comment_id', 'referencedColumnName' => 'id')),
73 $metadata->addLifecycleCallback('loading', 'postLoad');
74 $metadata->addLifecycleCallback('willBeRemoved', 'preRemove');
75 $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
77 $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
82 private function generateEntityTypeFixture(array $field)
84 $metadata = new ClassMetadataInfo($this->_namespace . '\EntityType');
85 $metadata->namespace = $this->_namespace;
87 $metadata->table['name'] = 'entity_type';
88 $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
89 $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
91 $name = $field['fieldName'];
92 $type = $field['dbType'];
93 $metadata->mapField(array('fieldName' => $name, 'type' => $type));
95 $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
101 * @param ClassMetadataInfo $metadata
102 * @return EntityGeneratorBook
104 public function newInstance($metadata)
106 $path = $this->_tmpDir . '/'. $this->_namespace . '/EntityGeneratorBook.php';
107 $this->assertFileExists($path);
110 return new $metadata->name;
113 public function testGeneratedEntityClass()
115 $metadata = $this->generateBookEntityFixture();
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.");
129 $this->assertEquals('published', $book->getStatus());
131 $book->setName('Jonathan H. Wage');
132 $this->assertEquals('Jonathan H. Wage', $book->getName());
134 $author = new EntityGeneratorAuthor();
135 $book->setAuthor($author);
136 $this->assertEquals($author, $book->getAuthor());
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());
146 public function testEntityUpdatingWorks()
148 $metadata = $this->generateBookEntityFixture();
149 $metadata->mapField(array('fieldName' => 'test', 'type' => 'string'));
151 $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
153 $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
155 $book = $this->newInstance($metadata);
156 $reflClass = new \ReflectionClass($metadata->name);
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'.");
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.");
170 public function testEntityExtendsStdClass()
172 $this->_generator->setClassToExtend('stdClass');
173 $metadata = $this->generateBookEntityFixture();
175 $book = $this->newInstance($metadata);
176 $this->assertInstanceOf('stdClass', $book);
179 public function testLifecycleCallbacks()
181 $metadata = $this->generateBookEntityFixture();
183 $book = $this->newInstance($metadata);
184 $reflClass = new \ReflectionClass($metadata->name);
186 $this->assertTrue($reflClass->hasMethod('loading'), "Check for postLoad lifecycle callback.");
187 $this->assertTrue($reflClass->hasMethod('willBeRemoved'), "Check for preRemove lifecycle callback.");
190 public function testLoadMetadata()
192 $metadata = $this->generateBookEntityFixture();
194 $book = $this->newInstance($metadata);
196 $cm = new \Doctrine\ORM\Mapping\ClassMetadata($metadata->name);
197 $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
199 $driver = $this->createAnnotationDriver();
200 $driver->loadMetadataForClass($cm->name, $cm);
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);
210 public function testLoadPrefixedMetadata()
212 $this->_generator->setAnnotationPrefix('ORM\\');
213 $metadata = $this->generateBookEntityFixture();
215 $reader = new \Doctrine\Common\Annotations\AnnotationReader();
216 $driver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader, array());
218 $book = $this->newInstance($metadata);
220 $cm = new \Doctrine\ORM\Mapping\ClassMetadata($metadata->name);
221 $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
223 $driver->loadMetadataForClass($cm->name, $cm);
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);
234 * @dataProvider getParseTokensInEntityFileData
236 public function testParseTokensInEntityFile($php, $classes)
238 $r = new \ReflectionObject($this->_generator);
239 $m = $r->getMethod('parseTokensInEntityFile');
240 $m->setAccessible(true);
242 $p = $r->getProperty('staticReflection');
243 $p->setAccessible(true);
245 $ret = $m->invoke($this->_generator, $php);
246 $this->assertEquals($classes, array_keys($p->getValue($this->_generator)));
252 public function testGenerateEntityWithSequenceGenerator()
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,
263 $this->_generator->writeEntityClass($metadata, $this->_tmpDir);
265 $filename = $this->_tmpDir . DIRECTORY_SEPARATOR
266 . $this->_namespace . DIRECTORY_SEPARATOR . 'DDC1784Entity.php';
268 $this->assertFileExists($filename);
269 require_once $filename;
272 $reflection = new \ReflectionProperty($metadata->name, 'id');
273 $docComment = $reflection->getDocComment();
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);
282 * @dataProvider getEntityTypeAliasDataProvider
286 public function testEntityTypeAlias(array $field)
288 $metadata = $this->generateEntityTypeFixture($field);
289 $path = $this->_tmpDir . '/'. $this->_namespace . '/EntityType.php';
291 $this->assertFileExists($path);
294 $entity = new $metadata->name;
295 $reflClass = new \ReflectionClass($metadata->name);
297 $type = $field['phpType'];
298 $name = $field['fieldName'];
299 $value = $field['value'];
300 $getter = "get" . ucfirst($name);
301 $setter = "set" . ucfirst($name);
303 $this->assertPhpDocVarType($type, $reflClass->getProperty($name));
304 $this->assertPhpDocParamType($type, $reflClass->getMethod($setter));
305 $this->assertPhpDocReturnType($type, $reflClass->getMethod($getter));
307 $this->assertSame($entity, $entity->{$setter}($value));
308 $this->assertEquals($value, $entity->{$getter}());
314 public function getEntityTypeAliasDataProvider()
318 'fieldName' => 'datetimetz',
319 'phpType' => '\\DateTime',
320 'dbType' => 'datetimetz',
321 'value' => new \DateTime
324 'fieldName' => 'datetime',
325 'phpType' => '\\DateTime',
326 'dbType' => 'datetime',
327 'value' => new \DateTime
330 'fieldName' => 'date',
331 'phpType' => '\\DateTime',
333 'value' => new \DateTime
336 'fieldName' => 'time',
337 'phpType' => '\DateTime',
339 'value' => new \DateTime
342 'fieldName' => 'object',
343 'phpType' => '\stdClass',
344 'dbType' => 'object',
345 'value' => new \stdClass()
348 'fieldName' => 'bigint',
349 'phpType' => 'integer',
350 'dbType' => 'bigint',
354 'fieldName' => 'smallint',
355 'phpType' => 'integer',
356 'dbType' => 'smallint',
360 'fieldName' => 'text',
361 'phpType' => 'string',
366 'fieldName' => 'blob',
367 'phpType' => 'string',
372 'fieldName' => 'decimal',
373 'phpType' => 'float',
374 'dbType' => 'decimal',
380 public function getParseTokensInEntityFileData()
384 '<?php namespace Foo\Bar; class Baz {}',
385 array('Foo\Bar\Baz'),
388 '<?php namespace Foo\Bar; use Foo; class Baz {}',
389 array('Foo\Bar\Baz'),
392 '<?php namespace /*Comment*/ Foo\Bar; /** Foo */class /* Comment */ Baz {}',
393 array('Foo\Bar\Baz'),
407 array('Foo\Bar\Baz'),
413 * @param string $type
414 * @param \ReflectionProperty $property
416 private function assertPhpDocVarType($type, \ReflectionProperty $property)
418 $this->assertEquals(1, preg_match('/@var\s+([^\s]+)/',$property->getDocComment(), $matches));
419 $this->assertEquals($type, $matches[1]);
423 * @param string $type
424 * @param \ReflectionProperty $method
426 private function assertPhpDocReturnType($type, \ReflectionMethod $method)
428 $this->assertEquals(1, preg_match('/@return\s+([^\s]+)/', $method->getDocComment(), $matches));
429 $this->assertEquals($type, $matches[1]);
433 * @param string $type
434 * @param \ReflectionProperty $method
436 private function assertPhpDocParamType($type, \ReflectionMethod $method)
438 $this->assertEquals(1, preg_match('/@param\s+([^\s]+)/', $method->getDocComment(), $matches));
439 $this->assertEquals($type, $matches[1]);
443 class EntityGeneratorAuthor {}
444 class EntityGeneratorComment {}