PageRenderTime 63ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php

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