PageRenderTime 42ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/Tests/Unit/Persistence/Generic/DataMapperTest.php

https://github.com/christianjul/FLOW3-Composer
PHP | 472 lines | 339 code | 62 blank | 71 comment | 0 complexity | 7439fe9f13fba6f6a8f0c855a4ad6738 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0
  1. <?php
  2. namespace TYPO3\FLOW3\Tests\Unit\Persistence\Generic;
  3. /* *
  4. * This script belongs to the FLOW3 package "TYPO3CR". *
  5. * *
  6. * It is free software; you can redistribute it and/or modify it under *
  7. * the terms of the GNU Lesser General Public License, either version 3 *
  8. * of the License, or (at your option) any later version. *
  9. * *
  10. * The TYPO3 project - inspiring people to share! *
  11. * */
  12. /**
  13. * Testcase for \TYPO3\FLOW3\Persistence\DataMapper
  14. *
  15. */
  16. class DataMapperTest extends \TYPO3\FLOW3\Tests\UnitTestCase {
  17. /**
  18. * @test
  19. * @expectedException \TYPO3\FLOW3\Persistence\Generic\Exception\InvalidObjectDataException
  20. */
  21. public function mapToObjectThrowsExceptionOnEmptyInput() {
  22. $objectData = array();
  23. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('dummy'));
  24. $dataMapper->_call('mapToObject', $objectData);
  25. }
  26. /**
  27. * @test
  28. */
  29. public function mapToObjectsMapsArrayToObjectByCallingmapToObject() {
  30. $objectData = array(array('identifier' => '1234'));
  31. $object = new \stdClass();
  32. $dataMapper = $this->getMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('mapToObject'));
  33. $dataMapper->expects($this->once())->method('mapToObject')->with($objectData[0])->will($this->returnValue($object));
  34. $dataMapper->mapToObjects($objectData);
  35. }
  36. /**
  37. * @test
  38. */
  39. public function mapToObjectReturnsObjectFromIdentityMapIfAvailable() {
  40. $objectData = array('identifier' => '1234');
  41. $object = new \stdClass();
  42. $mockSession = $this->getMock('TYPO3\FLOW3\Persistence\Generic\Session');
  43. $mockSession->expects($this->once())->method('hasIdentifier')->with('1234')->will($this->returnValue(TRUE));
  44. $mockSession->expects($this->once())->method('getObjectByIdentifier')->with('1234')->will($this->returnValue($object));
  45. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('dummy'));
  46. $dataMapper->injectPersistenceSession($mockSession);
  47. $dataMapper->_call('mapToObject', $objectData);
  48. }
  49. /**
  50. * Test that an object is reconstituted, registered with the identity map
  51. * and memorizes it's clean state.
  52. *
  53. * @test
  54. */
  55. public function mapToObjectReconstitutesExpectedObjectAndRegistersItWithIdentitymapToObjects() {
  56. $mockEntityClassName = 'Entity' . md5(uniqid(mt_rand(), TRUE));
  57. $mockEntity = $this->getMock('TYPO3\FLOW3\Aop\ProxyInterface', array('FLOW3_Aop_Proxy_invokeJoinPoint', '__wakeup'), array(), $mockEntityClassName);
  58. $objectData = array('identifier' => '1234', 'classname' => $mockEntityClassName, 'properties' => array('foo'));
  59. $mockClassSchema = $this->getMock('TYPO3\FLOW3\Reflection\ClassSchema', array(), array(), '', FALSE);
  60. $mockClassSchema->expects($this->any())->method('getModelType')->will($this->returnValue(\TYPO3\FLOW3\Reflection\ClassSchema::MODELTYPE_ENTITY));
  61. $mockReflectionService = $this->getMock('TYPO3\FLOW3\Reflection\ReflectionService', array(), array(), '', FALSE);
  62. $mockReflectionService->expects($this->any())->method('getClassSchema')->with($mockEntityClassName)->will($this->returnValue($mockClassSchema));
  63. $mockSession = $this->getMock('TYPO3\FLOW3\Persistence\Generic\Session');
  64. $mockSession->expects($this->once())->method('registerReconstitutedEntity')->with($mockEntity, $objectData);
  65. $mockSession->expects($this->once())->method('registerObject')->with($mockEntity, '1234');
  66. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('thawProperties'));
  67. $dataMapper->expects($this->once())->method('thawProperties')->with($mockEntity, $objectData['identifier'], $objectData);
  68. $dataMapper->injectPersistenceSession($mockSession);
  69. $dataMapper->injectReflectionService($mockReflectionService);
  70. $dataMapper->_call('mapToObject', $objectData);
  71. }
  72. /**
  73. * @test
  74. */
  75. public function thawPropertiesSetsPropertyValues() {
  76. $className = 'Class' . md5(uniqid(mt_rand(), TRUE));
  77. eval('class ' . $className . ' { public $firstProperty; public $secondProperty; public $thirdProperty; public $fourthProperty; }');
  78. $object = new $className();
  79. $objectData = array(
  80. 'identifier' => '1234',
  81. 'classname' => 'TYPO3\Post',
  82. 'properties' => array(
  83. 'firstProperty' => array(
  84. 'type' => 'string',
  85. 'multivalue' => FALSE,
  86. 'value' => 'firstValue'
  87. ),
  88. 'secondProperty' => array(
  89. 'type' => 'integer',
  90. 'multivalue' => FALSE,
  91. 'value' => 1234
  92. ),
  93. 'thirdProperty' => array(
  94. 'type' => 'float',
  95. 'multivalue' => FALSE,
  96. 'value' => 1.234
  97. ),
  98. 'fourthProperty' => array(
  99. 'type' => 'boolean',
  100. 'multivalue' => FALSE,
  101. 'value' => FALSE
  102. )
  103. )
  104. );
  105. $classSchema = new \TYPO3\FLOW3\Reflection\ClassSchema('TYPO3\Post');
  106. $classSchema->addProperty('firstProperty', 'string');
  107. $classSchema->addProperty('secondProperty', 'integer');
  108. $classSchema->addProperty('thirdProperty', 'float');
  109. $classSchema->addProperty('fourthProperty', 'boolean');
  110. $mockReflectionService = $this->getMock('TYPO3\FLOW3\Reflection\ReflectionService');
  111. $mockReflectionService->expects($this->once())->method('getClassSchema')->will($this->returnValue($classSchema));
  112. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('dummy'));
  113. $dataMapper->injectReflectionService($mockReflectionService);
  114. $dataMapper->_call('thawProperties', $object, 1234, $objectData);
  115. $this->assertAttributeEquals('firstValue', 'firstProperty', $object);
  116. $this->assertAttributeEquals(1234, 'secondProperty', $object);
  117. $this->assertAttributeEquals(1.234, 'thirdProperty', $object);
  118. $this->assertAttributeEquals(FALSE, 'fourthProperty', $object);
  119. }
  120. /**
  121. * After thawing the properties, the nodes' uuid will be available in the identifier
  122. * property of the proxy class.
  123. *
  124. * @test
  125. */
  126. public function thawPropertiesAssignsTheUuidToTheProxy() {
  127. $className = 'Class' . md5(uniqid(mt_rand(), TRUE));
  128. eval('class ' . $className . ' { public $FLOW3_Persistence_Entity_UUID; }');
  129. $object = new $className();
  130. $objectData = array(
  131. 'identifier' => 'c254d2e0-825a-11de-8a39-0800200c9a66',
  132. 'classname' => 'TYPO3\Post',
  133. 'properties' => array()
  134. );
  135. $classSchema = new \TYPO3\FLOW3\Reflection\ClassSchema('TYPO3\Post');
  136. $mockReflectionService = $this->getMock('TYPO3\FLOW3\Reflection\ReflectionService');
  137. $mockReflectionService->expects($this->once())->method('getClassSchema')->will($this->returnValue($classSchema));
  138. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('dummy'));
  139. $dataMapper->injectReflectionService($mockReflectionService);
  140. $dataMapper->_call('thawProperties', $object, $objectData['identifier'], $objectData);
  141. $this->assertAttributeEquals('c254d2e0-825a-11de-8a39-0800200c9a66', 'FLOW3_Persistence_Identifier', $object);
  142. }
  143. /**
  144. * @test
  145. */
  146. public function thawPropertiesDelegatesHandlingOfArraysAndObjects() {
  147. $className = 'Class' . md5(uniqid(mt_rand(), TRUE));
  148. eval('class ' . $className . ' { public $firstProperty; public $secondProperty; public $thirdProperty; public $fourthProperty; }');
  149. $object = new $className();
  150. $objectData = array(
  151. 'identifier' => '1234',
  152. 'classname' => 'TYPO3\Post',
  153. 'properties' => array(
  154. 'firstProperty' => array(
  155. 'type' => 'array',
  156. 'multivalue' => TRUE,
  157. 'value' => array(array('type' => 'string', 'index' => 0, 'value' => 'theMappedArray'))
  158. ),
  159. 'secondProperty' => array(
  160. 'type' => 'SplObjectStorage',
  161. 'multivalue' => TRUE,
  162. 'value' => array(array('type' => 'Some\Object', 'index' => NULL, 'value' => 'theMappedSplObjectStorage'))
  163. ),
  164. 'thirdProperty' => array(
  165. 'type' => 'DateTime',
  166. 'multivalue' => FALSE,
  167. 'value' => 'theUnixtime'
  168. ),
  169. 'fourthProperty' => array(
  170. 'type' => '\TYPO3\Some\Domain\Model',
  171. 'multivalue' => FALSE,
  172. 'value' => array('identifier' => 'theMappedObjectIdentifier')
  173. )
  174. )
  175. );
  176. $classSchema = new \TYPO3\FLOW3\Reflection\ClassSchema('TYPO3\Post');
  177. $classSchema->addProperty('firstProperty', 'array');
  178. $classSchema->addProperty('secondProperty', 'SplObjectStorage');
  179. $classSchema->addProperty('thirdProperty', 'DateTime');
  180. $classSchema->addProperty('fourthProperty', '\TYPO3\Some\Domain\Model');
  181. $mockReflectionService = $this->getMock('TYPO3\FLOW3\Reflection\ReflectionService');
  182. $mockReflectionService->expects($this->once())->method('getClassSchema')->will($this->returnValue($classSchema));
  183. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('mapDateTime', 'mapArray', 'mapSplObjectStorage', 'mapToObject'));
  184. $dataMapper->injectReflectionService($mockReflectionService);
  185. $dataMapper->expects($this->at(0))->method('mapArray')->with($objectData['properties']['firstProperty']['value']);
  186. $dataMapper->expects($this->at(1))->method('mapSplObjectStorage')->with($objectData['properties']['secondProperty']['value']);
  187. $dataMapper->expects($this->at(2))->method('mapDateTime')->with($objectData['properties']['thirdProperty']['value']);
  188. $dataMapper->expects($this->at(3))->method('mapToObject')->with($objectData['properties']['fourthProperty']['value']);
  189. $dataMapper->_call('thawProperties', $object, $objectData['identifier'], $objectData);
  190. }
  191. /**
  192. * @test
  193. * @see http://forge.typo3.org/issues/9684
  194. * @todo check for correct order again, somehow...
  195. */
  196. public function thawPropertiesFollowsOrderOfGivenObjectData() {
  197. $this->markTestSkipped('The test needs to check for the correct order again, somehow....');
  198. $className = 'Class' . md5(uniqid(mt_rand(), TRUE));
  199. eval('class ' . $className . ' { public $firstProperty; public $secondProperty; public $thirdProperty; }');
  200. $object = new $className();
  201. $objectData = array(
  202. 'identifier' => '1234',
  203. 'classname' => 'TYPO3\Post',
  204. 'properties' => array(
  205. 'secondProperty' => array(
  206. 'type' => 'string',
  207. 'multivalue' => FALSE,
  208. 'value' => 'secondValue'
  209. ),
  210. 'firstProperty' => array(
  211. 'type' => 'string',
  212. 'multivalue' => FALSE,
  213. 'value' => 'firstValue'
  214. ),
  215. 'thirdProperty' => array(
  216. 'type' => 'string',
  217. 'multivalue' => FALSE,
  218. 'value' => 'thirdValue'
  219. )
  220. )
  221. );
  222. $classSchema = new \TYPO3\FLOW3\Reflection\ClassSchema('TYPO3\Post');
  223. $classSchema->addProperty('firstProperty', 'string');
  224. $classSchema->addProperty('secondProperty', 'string');
  225. $classSchema->addProperty('thirdProperty', 'string');
  226. $mockReflectionService = $this->getMock('TYPO3\FLOW3\Reflection\ReflectionService');
  227. $mockReflectionService->expects($this->once())->method('getClassSchema')->will($this->returnValue($classSchema));
  228. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('dummy'));
  229. $dataMapper->injectReflectionService($mockReflectionService);
  230. $dataMapper->_call('thawProperties', $object, 1234, $objectData);
  231. // the order of setting those is important, but cannot be tested for now (static setProperty)
  232. $this->assertAttributeEquals('secondValue', 'secondProperty', $object);
  233. $this->assertAttributeEquals('firstValue', 'firstProperty', $object);
  234. $this->assertAttributeEquals('thirdValue', 'thirdProperty', $object);
  235. }
  236. /**
  237. * If a property has been removed from a class old data still in the persistence
  238. * must be skipped when reconstituting.
  239. *
  240. * @test
  241. */
  242. public function thawPropertiesSkipsPropertiesNoLongerInClassSchema() {
  243. $className = 'Class' . md5(uniqid(mt_rand(), TRUE));
  244. eval('class ' . $className . ' { public $firstProperty; public $thirdProperty; }');
  245. $object = new $className();
  246. $objectData = array(
  247. 'identifier' => '1234',
  248. 'classname' => 'TYPO3\Post',
  249. 'properties' => array(
  250. 'firstProperty' => array(
  251. 'type' => 'string',
  252. 'multivalue' => FALSE,
  253. 'value' => 'firstValue'
  254. ),
  255. 'secondProperty' => array(
  256. 'type' => 'string',
  257. 'multivalue' => FALSE,
  258. 'value' => 'secondValue'
  259. ),
  260. 'thirdProperty' => array(
  261. 'type' => 'string',
  262. 'multivalue' => FALSE,
  263. 'value' => 'thirdValue'
  264. )
  265. )
  266. );
  267. $classSchema = new \TYPO3\FLOW3\Reflection\ClassSchema('TYPO3\Post');
  268. $classSchema->addProperty('firstProperty', 'string');
  269. $classSchema->addProperty('thirdProperty', 'string');
  270. $mockReflectionService = $this->getMock('TYPO3\FLOW3\Reflection\ReflectionService');
  271. $mockReflectionService->expects($this->once())->method('getClassSchema')->will($this->returnValue($classSchema));
  272. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('dummy'));
  273. $dataMapper->injectReflectionService($mockReflectionService);
  274. $dataMapper->_call('thawProperties', $object, 1234, $objectData);
  275. $this->assertObjectNotHasAttribute('secondProperty', $object);
  276. }
  277. /**
  278. * After thawing the properties, metadata in the object data will be set
  279. * as a special proxy property.
  280. *
  281. * @test
  282. */
  283. public function thawPropertiesAssignsMetadataToTheProxyIfItExists() {
  284. $className = 'Class' . md5(uniqid(mt_rand(), TRUE));
  285. eval('class ' . $className . ' { public $FLOW3_Persistence_Metadata; }');
  286. $object = new $className();
  287. $objectData = array(
  288. 'identifier' => 'c254d2e0-825a-11de-8a39-0800200c9a66',
  289. 'classname' => 'TYPO3\Post',
  290. 'properties' => array(),
  291. 'metadata' => array('My_Metadata' => 'Test')
  292. );
  293. $classSchema = new \TYPO3\FLOW3\Reflection\ClassSchema('TYPO3\Post');
  294. $mockReflectionService = $this->getMock('TYPO3\FLOW3\Reflection\ReflectionService');
  295. $mockReflectionService->expects($this->once())->method('getClassSchema')->will($this->returnValue($classSchema));
  296. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('dummy'));
  297. $dataMapper->injectReflectionService($mockReflectionService);
  298. $dataMapper->_call('thawProperties', $object, $objectData['identifier'], $objectData);
  299. $this->assertAttributeEquals(array('My_Metadata' => 'Test'), 'FLOW3_Persistence_Metadata', $object);
  300. }
  301. /**
  302. * @test
  303. */
  304. public function mapSplObjectStorageCreatesSplObjectStorage() {
  305. $objectData = array(
  306. array('value' => array('mappedObject1')),
  307. array('value' => array('mappedObject2'))
  308. );
  309. $classSchema = new \TYPO3\FLOW3\Reflection\ClassSchema('TYPO3\Post');
  310. $classSchema->addProperty('firstProperty', 'SplObjectStorage');
  311. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('mapToObject'));
  312. $dataMapper->expects($this->at(0))->method('mapToObject')->with($objectData[0]['value'])->will($this->returnValue(new \stdClass()));
  313. $dataMapper->expects($this->at(1))->method('mapToObject')->with($objectData[1]['value'])->will($this->returnValue(new \stdClass()));
  314. $dataMapper->_call('mapSplObjectStorage', $objectData);
  315. }
  316. /**
  317. * @test
  318. */
  319. public function mapDateTimeCreatesDateTimeFromTimestamp() {
  320. $expected = new \DateTime();
  321. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('dummy'));
  322. $this->assertEquals($dataMapper->_call('mapDateTime', $expected->getTimestamp()), $expected);
  323. }
  324. /**
  325. * @test
  326. */
  327. public function mapArrayCreatesExpectedArray() {
  328. $dateTime = new \DateTime();
  329. $object = new \stdClass();
  330. $splObjectStorage = new \SplObjectStorage();
  331. $expected = array(
  332. 'one' => 'onetwothreefour',
  333. 'two' => 1234,
  334. 'three' => 1.234,
  335. 'four' => FALSE,
  336. 'five' => $dateTime,
  337. 'six' => $object,
  338. 'seven' => $splObjectStorage
  339. );
  340. $arrayValues = array(
  341. 'one' => array(
  342. 'type' => 'string',
  343. 'index' => 'one',
  344. 'value' => 'onetwothreefour'
  345. ),
  346. 'two' => array(
  347. 'type' => 'integer',
  348. 'index' => 'two',
  349. 'value' => 1234
  350. ),
  351. 'three' => array(
  352. 'type' => 'float',
  353. 'index' => 'three',
  354. 'value' => 1.234
  355. ),
  356. 'four' => array(
  357. 'type' => 'boolean',
  358. 'index' => 'four',
  359. 'value' => FALSE
  360. ),
  361. 'five' => array(
  362. 'type' => 'DateTime',
  363. 'index' => 'five',
  364. 'value' => $dateTime->getTimestamp()
  365. ),
  366. 'six' => array(
  367. 'type' => 'stdClass',
  368. 'index' => 'six',
  369. 'value' => array('mappedObject')
  370. ),
  371. 'seven' => array(
  372. 'type' => 'SplObjectStorage',
  373. 'index' => 'seven',
  374. 'value' => array('mappedObject')
  375. )
  376. );
  377. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('mapDateTime', 'mapToObject', 'mapSplObjectStorage'));
  378. $dataMapper->expects($this->once())->method('mapDateTime')->with($arrayValues['five']['value'])->will($this->returnValue($dateTime));
  379. $dataMapper->expects($this->once())->method('mapToObject')->with($arrayValues['six']['value'])->will($this->returnValue($object));
  380. $dataMapper->expects($this->once())->method('mapSplObjectStorage')->with($arrayValues['seven']['value'])->will($this->returnValue($splObjectStorage));
  381. $this->assertEquals($dataMapper->_call('mapArray', $arrayValues), $expected);
  382. }
  383. /**
  384. * @test
  385. */
  386. public function mapArrayMapsNestedArray() {
  387. $arrayValues = array(
  388. 'one' => array(
  389. 'type' => 'array',
  390. 'index' => 'foo',
  391. 'value' => array(
  392. array(
  393. 'type' => 'string',
  394. 'index' => 'bar',
  395. 'value' => 'baz'
  396. ),
  397. array(
  398. 'type' => 'integer',
  399. 'index' => 'quux',
  400. 'value' => NULL
  401. )
  402. )
  403. )
  404. );
  405. $expected = array('foo' => array('bar' => 'baz', 'quux' => NULL));
  406. $dataMapper = $this->getAccessibleMock('TYPO3\FLOW3\Persistence\Generic\DataMapper', array('dummy'));
  407. $this->assertEquals($expected, $dataMapper->_call('mapArray', $arrayValues));
  408. }
  409. }
  410. ?>