diff --git a/Tests/Unit/Tools/Mapper/MapperTest.php b/Tests/Unit/Tools/Mapper/MapperTest.php index cd26ff1e..954bd7cb 100644 --- a/Tests/Unit/Tools/Mapper/MapperTest.php +++ b/Tests/Unit/Tools/Mapper/MapperTest.php @@ -268,4 +268,107 @@ public function provideEmptyValues() yield 'Empty allowed option' => [['name' => ''], '', $ctx]; yield 'Wrong type' => [null, null, $ctx]; } + + /** + * @dataProvider provideMergeMappings + */ + public function testShouldMergeMappings($elements, $mappers, $mockedMapFunction, $mockedMapAllFunction, $expectedResult) + { + $mapperMock = $this->getMockBuilder(Mapper::class) + ->setMethods(['mapAll', 'map']) + ->getMock(); + + $mapperMock->method('map')->willReturn($mockedMapFunction); + $mapperMock->method('mapAll')->willReturn($mockedMapAllFunction); + + $result = $mapperMock->mergeMapping($elements, 'mappingName', $mappers); + + $this->assertSame($expectedResult, $result); + } + + public function provideMergeMappings() + { + yield 'Merge mappings' => [ + [ + 'packshot' => 'url://packshot.com', + 'lengow' => null, + 'eRetail' => [ + 'main' => 'url://main.com', + 'nonBrand' => [ + 'url://nonBrand1.com', + 'url://nonBrand2.com' + ] + ] + ], + [ + ['map', 'packshot'], + ['map', 'lengow'], + ['map', 'maps'], + ['map', 'eRetail.main'], + ['mapAll', 'eRetail.nonBrand'], + ], + ['name' => 'singleLine', 'location' => 'https://media.com/1'], + [['name' => 'multipleLines', 'location' => 'https://media.com/2'],['name' => 'multipleLines', 'location' => 'https://media.com/3']], + [ + ['name' => 'singleLine', 'location' => 'https://media.com/1'], + ['name' => 'singleLine', 'location' => 'https://media.com/1'], + ['name' => 'multipleLines', 'location' => 'https://media.com/2'], + ['name' => 'multipleLines', 'location' => 'https://media.com/3'] + ], + ]; + yield 'Merge mappings with null mapAll' => [ + [ + 'line' => 'https://media.com/1', + 'lines' => null + ], + [ + ['map', 'line'], + ['mapAll', 'lines'], + ], + ['name' => 'singleLine', 'location' => 'https://media.com/1'], + null, + [ + ['name' => 'singleLine', 'location' => 'https://media.com/1'] + ], + ]; + yield 'Merge mappings with null map' => [ + [ + 'line' => null, + 'lines' => [ + 'https://media.com/2', + 'https://media.com/3' + ] + ], + [ + ['map', 'line'], + ['mapAll', 'lines'], + ], + null, + [['name' => 'multipleLines', 'location' => 'https://media.com/2'],['name' => 'multipleLines', 'location' => 'https://media.com/3']], + [ + ['name' => 'multipleLines', 'location' => 'https://media.com/2'], + ['name' => 'multipleLines', 'location' => 'https://media.com/3'] + ], + ]; + } + + /** + * @dataProvider provideInvalidMappersToMerge + */ + public function testShouldThrowExceptionIfMappersIsNotCorrect(array $mapper = null) + { + $this->expectException(\InvalidArgumentException::class); + $this->mapper->mergeMapping([ + 'line' => 'https://media.com/1', + 'lines' => ['https://media.com/2','https://media.com/3'] + ], 'test', $mapper); +// $this->assertTrue(true); + } + + public function provideInvalidMappersToMerge() + { + yield 'Null mappers parameter' => [null]; + yield 'Map function is not mapped' => [[['invalid', 'line']]]; + yield 'Map function is null' => [[[null, 'line']]]; + } } diff --git a/Tools/Mapper/Mapper.php b/Tools/Mapper/Mapper.php index 320515f2..33ef2614 100644 --- a/Tools/Mapper/Mapper.php +++ b/Tools/Mapper/Mapper.php @@ -89,6 +89,66 @@ public function map($obj, $mappingName, $context = []) return $this->resolve($mapping, $obj, $context); } + /** + * Merge multiples arrays values in a single mappingName + * + * @param array $elements + * @param string $mappingName + * @param array $mappers + * + * @return null|string + */ + public function mergeMapping($elements, $mappingName, $mappers) + { + if(empty($elements)) { + return null; + } + + if (empty($mappers)) { + throw new \InvalidArgumentException('No mapper provided.'); + } + + $response = []; + + foreach ($mappers as $mapper){ + $object = $this->getObject($elements, $mapper[1]); + if(empty($object)){ + continue; + } + + $mapFunction = $mapper[0] ?? null; + $context = $mapper[2] ?? $mapper[1] ?? null; + + if(empty($mapFunction) || empty($context) || !in_array($mapFunction, ['map', 'mapAll'])){ + throw new \InvalidArgumentException('No mapper function or context informed'); + } + + $mappedObject = $this->$mapFunction($object, $mappingName, $context); + if (!empty($mappedObject)) { + $response = ($mapFunction === 'map') + ? array_merge($response, [$mappedObject]) + : array_merge($response, $mappedObject); + } + } + + return $response; + } + + + private function getObject(array $elements, string $path) { + $keys = explode('.', $path); + $current = $elements; + + foreach ($keys as $key) { + if (!isset($current[$key])) { + return null; + } + $current = $current[$key]; + } + + return $current; + } + /** * @param $mapping * @param $obj