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