[TASK] Remove ext:dbal from installation steps
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Property / TypeConverter / PersistentObjectConverterTest.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter;
3
4 /* *
5 * This script belongs to the Extbase framework. *
6 * *
7 * It is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU Lesser General Public License as published by the *
9 * Free Software Foundation, either version 3 of the License, or (at your *
10 * option) any later version. *
11 * *
12 * This script is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
14 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
15 * General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with the script. *
19 * If not, see http://www.gnu.org/licenses/lgpl.html *
20 * *
21 * The TYPO3 project - inspiring people to share! *
22 * */
23 use TYPO3\CMS\Core\Tests\UnitTestCase;
24 use TYPO3\CMS\Extbase\Property\Exception\DuplicateObjectException;
25 use TYPO3\CMS\Extbase\Property\Exception\InvalidPropertyMappingConfigurationException;
26 use TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException;
27 use TYPO3\CMS\Extbase\Property\Exception\TargetNotFoundException;
28 use TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter;
29 use TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter\Fixtures\PersistentObjectEntityFixture;
30 use TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter\Fixtures\PersistentObjectFixture;
31 use TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter\Fixtures\PersistentObjectValueObjectFixture;
32
33 /**
34 * Test case
35 */
36 class PersistentObjectConverterTest extends UnitTestCase
37 {
38 /**
39 * @var \TYPO3\CMS\Extbase\Property\TypeConverterInterface|\PHPUnit_Framework_MockObject_MockObject
40 */
41 protected $converter;
42
43 /**
44 * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService|\PHPUnit_Framework_MockObject_MockObject
45 */
46 protected $mockReflectionService;
47
48 /**
49 * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface|\PHPUnit_Framework_MockObject_MockObject
50 */
51 protected $mockPersistenceManager;
52
53 /**
54 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
55 */
56 protected $mockObjectManager;
57
58 /**
59 * @var \TYPO3\CMS\Extbase\Object\Container\Container|\PHPUnit_Framework_MockObject_MockObject
60 */
61 protected $mockContainer;
62
63 /**
64 * @throws \InvalidArgumentException
65 * @throws \PHPUnit_Framework_Exception
66 * @throws \RuntimeException
67 */
68 protected function setUp()
69 {
70 $this->converter = new PersistentObjectConverter();
71 $this->mockReflectionService = $this->createMock(\TYPO3\CMS\Extbase\Reflection\ReflectionService::class);
72 $this->inject($this->converter, 'reflectionService', $this->mockReflectionService);
73
74 $this->mockPersistenceManager = $this->createMock(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface::class);
75 $this->inject($this->converter, 'persistenceManager', $this->mockPersistenceManager);
76
77 $this->mockObjectManager = $this->createMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
78 $this->mockObjectManager->expects($this->any())
79 ->method('get')
80 ->will($this->returnCallback(function ($className, ...$arguments) {
81 $reflectionClass = new \ReflectionClass($className);
82 if (empty($arguments)) {
83 return $reflectionClass->newInstance();
84 } else {
85 return $reflectionClass->newInstanceArgs($arguments);
86 }
87 }));
88 $this->inject($this->converter, 'objectManager', $this->mockObjectManager);
89
90 $this->mockContainer = $this->createMock(\TYPO3\CMS\Extbase\Object\Container\Container::class);
91 $this->inject($this->converter, 'objectContainer', $this->mockContainer);
92 }
93
94 /**
95 * @test
96 */
97 public function checkMetadata()
98 {
99 $this->assertEquals(['integer', 'string', 'array'], $this->converter->getSupportedSourceTypes(), 'Source types do not match');
100 $this->assertEquals('object', $this->converter->getSupportedTargetType(), 'Target type does not match');
101 $this->assertEquals(1, $this->converter->getPriority(), 'Priority does not match');
102 }
103
104 /**
105 * @return array
106 */
107 public function dataProviderForCanConvert()
108 {
109 return [
110 [true, false, true],
111 // is entity => can convert
112 [false, true, true],
113 // is valueobject => can convert
114 [false, false, false],
115 // is no entity and no value object => can not convert
116 ];
117 }
118
119 /**
120 * @test
121 * @dataProvider dataProviderForCanConvert
122 */
123 public function canConvertFromReturnsTrueIfClassIsTaggedWithEntityOrValueObject($isEntity, $isValueObject, $expected)
124 {
125 $className = PersistentObjectFixture::class;
126
127 if ($isEntity) {
128 $className = PersistentObjectEntityFixture::class;
129 } elseif ($isValueObject) {
130 $className = PersistentObjectValueObjectFixture::class;
131 }
132 $this->assertEquals($expected, $this->converter->canConvertFrom('myInputData', $className));
133 }
134
135 /**
136 * @test
137 */
138 public function getSourceChildPropertiesToBeConvertedReturnsAllPropertiesExceptTheIdentityProperty()
139 {
140 $source = [
141 'k1' => 'v1',
142 '__identity' => 'someIdentity',
143 'k2' => 'v2'
144 ];
145 $expected = [
146 'k1' => 'v1',
147 'k2' => 'v2'
148 ];
149 $this->assertEquals($expected, $this->converter->getSourceChildPropertiesToBeConverted($source));
150 }
151
152 /**
153 * @test
154 */
155 public function getTypeOfChildPropertyShouldUseReflectionServiceToDetermineType()
156 {
157 $mockSchema = $this->getMockBuilder(\TYPO3\CMS\Extbase\Reflection\ClassSchema::class)->disableOriginalConstructor()->getMock();
158 $this->mockReflectionService->expects($this->any())->method('getClassSchema')->with('TheTargetType')->will($this->returnValue($mockSchema));
159
160 $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue('TheTargetType'));
161 $mockSchema->expects($this->any())->method('hasProperty')->with('thePropertyName')->will($this->returnValue(true));
162 $mockSchema->expects($this->any())->method('getProperty')->with('thePropertyName')->will($this->returnValue([
163 'type' => 'TheTypeOfSubObject',
164 'elementType' => null
165 ]));
166 $configuration = $this->buildConfiguration([]);
167 $this->assertEquals('TheTypeOfSubObject', $this->converter->getTypeOfChildProperty('TheTargetType', 'thePropertyName', $configuration));
168 }
169
170 /**
171 * @test
172 */
173 public function getTypeOfChildPropertyShouldUseConfiguredTypeIfItWasSet()
174 {
175 $this->mockReflectionService->expects($this->never())->method('getClassSchema');
176 $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue('foo'));
177
178 $configuration = $this->buildConfiguration([]);
179 $configuration->forProperty('thePropertyName')->setTypeConverterOption(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, PersistentObjectConverter::CONFIGURATION_TARGET_TYPE, 'Foo\Bar');
180 $this->assertEquals('Foo\Bar', $this->converter->getTypeOfChildProperty('foo', 'thePropertyName', $configuration));
181 }
182
183 /**
184 * @test
185 */
186 public function convertFromShouldFetchObjectFromPersistenceIfUuidStringIsGiven()
187 {
188 $identifier = '17';
189 $object = new \stdClass();
190
191 $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
192 $this->assertSame($object, $this->converter->convertFrom($identifier, 'MySpecialType'));
193 }
194
195 /**
196 * @test
197 */
198 public function convertFromShouldFetchObjectFromPersistenceIfuidStringIsGiven()
199 {
200 $identifier = '17';
201 $object = new \stdClass();
202
203 $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
204 $this->assertSame($object, $this->converter->convertFrom($identifier, 'MySpecialType'));
205 }
206
207 /**
208 * @test
209 */
210 public function convertFromShouldFetchObjectFromPersistenceIfOnlyIdentityArrayGiven()
211 {
212 $identifier = '12345';
213 $object = new \stdClass();
214
215 $source = [
216 '__identity' => $identifier
217 ];
218 $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
219 $this->assertSame($object, $this->converter->convertFrom($source, 'MySpecialType'));
220 }
221
222 /**
223 * @test
224 */
225 public function convertFromShouldThrowExceptionIfObjectNeedsToBeModifiedButConfigurationIsNotSet()
226 {
227 $this->expectException(InvalidPropertyMappingConfigurationException::class);
228 $this->expectExceptionCode(1297932028);
229 $identifier = '12345';
230 $object = new \stdClass();
231 $object->someProperty = 'asdf';
232
233 $source = [
234 '__identity' => $identifier,
235 'foo' => 'bar'
236 ];
237 $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
238 $this->converter->convertFrom($source, 'MySpecialType');
239 }
240
241 /**
242 * @param array $typeConverterOptions
243 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration
244 */
245 protected function buildConfiguration($typeConverterOptions)
246 {
247 $configuration = new \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration();
248 $configuration->setTypeConverterOptions(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, $typeConverterOptions);
249 return $configuration;
250 }
251
252 /**
253 * @param int $numberOfResults
254 * @param Matcher $howOftenIsGetFirstCalled
255 * @return \stdClass
256 */
257 public function setupMockQuery($numberOfResults, $howOftenIsGetFirstCalled)
258 {
259 $mockClassSchema = $this->getMockBuilder(\TYPO3\CMS\Extbase\Reflection\ClassSchema::class)
260 ->setConstructorArgs(['Dummy'])
261 ->getMock();
262 $mockClassSchema->expects($this->any())->method('getIdentityProperties')->will($this->returnValue(['key1' => 'someType']));
263 $this->mockReflectionService->expects($this->any())->method('getClassSchema')->with('SomeType')->will($this->returnValue($mockClassSchema));
264
265 $mockConstraint = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Comparison::class)->disableOriginalConstructor()->getMock();
266
267 $mockObject = new \stdClass();
268 $mockQuery = $this->createMock(\TYPO3\CMS\Extbase\Persistence\QueryInterface::class);
269 $mockQueryResult = $this->createMock(\TYPO3\CMS\Extbase\Persistence\QueryResultInterface::class);
270 $mockQueryResult->expects($this->any())->method('count')->will($this->returnValue($numberOfResults));
271 $mockQueryResult->expects($howOftenIsGetFirstCalled)->method('getFirst')->will($this->returnValue($mockObject));
272 $mockQuery->expects($this->any())->method('equals')->with('key1', 'value1')->will($this->returnValue($mockConstraint));
273 $mockQuery->expects($this->any())->method('matching')->with($mockConstraint)->will($this->returnValue($mockQuery));
274 $mockQuery->expects($this->any())->method('execute')->will($this->returnValue($mockQueryResult));
275
276 $this->mockPersistenceManager->expects($this->any())->method('createQueryForType')->with('SomeType')->will($this->returnValue($mockQuery));
277
278 return $mockObject;
279 }
280
281 /**
282 * @test
283 */
284 public function convertFromShouldReturnExceptionIfNoMatchingObjectWasFound()
285 {
286 $this->expectException(TargetNotFoundException::class);
287 $this->expectExceptionCode(1297933823);
288 $this->setupMockQuery(0, $this->never());
289 $this->mockReflectionService->expects($this->never())->method('getClassSchema');
290
291 $source = [
292 '__identity' => 123
293 ];
294 $actual = $this->converter->convertFrom($source, 'SomeType');
295 $this->assertNull($actual);
296 }
297
298 /**
299 * @test
300 */
301 public function convertFromShouldThrowExceptionIfMoreThanOneObjectWasFound()
302 {
303 $this->expectException(DuplicateObjectException::class);
304 // @TODO expectExceptionCode is 0
305 $this->setupMockQuery(2, $this->never());
306
307 $source = [
308 '__identity' => 666
309 ];
310 $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with(666)->will($this->throwException(new DuplicateObjectException));
311 $this->converter->convertFrom($source, 'SomeType');
312 }
313
314 /**
315 * @test
316 */
317 public function convertFromShouldThrowExceptionIfObjectNeedsToBeCreatedButConfigurationIsNotSet()
318 {
319 $this->expectException(InvalidPropertyMappingConfigurationException::class);
320 // @TODO expectExceptionCode is 0
321 $source = [
322 'foo' => 'bar'
323 ];
324 $this->converter->convertFrom($source, 'MySpecialType');
325 }
326
327 /**
328 * @test
329 */
330 public function convertFromShouldCreateObject()
331 {
332 $source = [
333 'propertyX' => 'bar'
334 ];
335 $convertedChildProperties = [
336 'property1' => 'bar'
337 ];
338 $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters();
339 $expectedObject->property1 = 'bar';
340
341 $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, '__construct')->will($this->throwException(new \ReflectionException()));
342 $configuration = $this->buildConfiguration([PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true]);
343 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, $convertedChildProperties, $configuration);
344 $this->assertEquals($expectedObject, $result);
345 }
346
347 /**
348 * @test
349 */
350 public function convertFromShouldThrowExceptionIfPropertyOnTargetObjectCouldNotBeSet()
351 {
352 $this->expectException(InvalidTargetException::class);
353 $this->expectExceptionCode(1297935345);
354 $source = [
355 'propertyX' => 'bar'
356 ];
357 $object = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters();
358 $convertedChildProperties = [
359 'propertyNotExisting' => 'bar'
360 ];
361 $this->mockObjectManager->expects($this->any())->method('get')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class)->will($this->returnValue($object));
362 $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, '__construct')->will($this->returnValue([]));
363 $configuration = $this->buildConfiguration([PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true]);
364 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, $convertedChildProperties, $configuration);
365 $this->assertSame($object, $result);
366 }
367
368 /**
369 * @test
370 */
371 public function convertFromShouldCreateObjectWhenThereAreConstructorParameters()
372 {
373 $source = [
374 'propertyX' => 'bar'
375 ];
376 $convertedChildProperties = [
377 'property1' => 'param1',
378 'property2' => 'bar'
379 ];
380 $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('param1');
381 $expectedObject->setProperty2('bar');
382
383 $this->mockReflectionService
384 ->expects($this->any())
385 ->method('getMethodParameters')
386 ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
387 ->will($this->returnValue([
388 'property1' => ['optional' => false]
389 ]));
390 $this->mockReflectionService
391 ->expects($this->any())
392 ->method('hasMethod')
393 ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
394 ->will($this->returnValue(true));
395 $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
396 $configuration = $this->buildConfiguration([PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true]);
397 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, $convertedChildProperties, $configuration);
398 $this->assertEquals($expectedObject, $result);
399 $this->assertEquals('bar', $expectedObject->getProperty2());
400 }
401
402 /**
403 * @test
404 */
405 public function convertFromShouldCreateObjectWhenThereAreOptionalConstructorParameters()
406 {
407 $source = [
408 'propertyX' => 'bar'
409 ];
410 $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('thisIsTheDefaultValue');
411
412 $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')->will($this->returnValue([
413 'property1' => ['optional' => true, 'defaultValue' => 'thisIsTheDefaultValue']
414 ]));
415 $this->mockReflectionService
416 ->expects($this->any())
417 ->method('hasMethod')
418 ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
419 ->will($this->returnValue(true));
420 $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
421 $configuration = $this->buildConfiguration([PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true]);
422 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, [], $configuration);
423 $this->assertEquals($expectedObject, $result);
424 }
425
426 /**
427 * @test
428 */
429 public function convertFromShouldThrowExceptionIfRequiredConstructorParameterWasNotFound()
430 {
431 $this->expectException(InvalidTargetException::class);
432 $this->expectExceptionCode(1268734872);
433 $source = [
434 'propertyX' => 'bar'
435 ];
436 $object = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('param1');
437 $convertedChildProperties = [
438 'property2' => 'bar'
439 ];
440
441 $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')->will($this->returnValue([
442 'property1' => ['optional' => false]
443 ]));
444 $this->mockReflectionService
445 ->expects($this->any())
446 ->method('hasMethod')
447 ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
448 ->will($this->returnValue(true));
449 $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
450 $configuration = $this->buildConfiguration([PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true]);
451 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, $convertedChildProperties, $configuration);
452 $this->assertSame($object, $result);
453 }
454
455 /**
456 * @test
457 */
458 public function convertFromShouldReturnNullForEmptyString()
459 {
460 $source = '';
461 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class);
462 $this->assertNull($result);
463 }
464 }