Skip to content

Commit

Permalink
fixed mergin arrays for mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
orlyk-rollun committed Jan 25, 2023
1 parent ac7e573 commit a702db9
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 1 deletion.
33 changes: 32 additions & 1 deletion src/Infrastructure/Mappers/SimpleSymfonyMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ public function mapFromArray(array $data, string|object $type): object
}
if (is_object($type)) {
$array = $this->mapToArray($type);
$data = Arr::mergeRecursive($array, $data);
// TODO
$data = $this->mergeArrays($array, $data);
$type = get_class($type);
}

Expand All @@ -63,4 +64,34 @@ protected function getIgnoredAttributes(array $data, string $type)

return array_diff(array_keys($data), $properties);
}

/**
* @todo Temp decision
* Проблема в тому, що індексовані масиви, котрі є простим полем, а не вложеним об'єктом,
* при рекурсивному об'єданні не заміняються, а додаються.
* Наприклад, якщо оригінальне значення ['a' => [1, 2]], а друге значення ['a' => [3]],
* то в результаті отримуємо ['a' => [1, 2, 3], а цього не потрібно робити при мапінгу -
* значення повинне замінитись на ['a' => [3].
* Потрібно або знайти інше рішення, або оптимізувати даний метод
*
* @param array $array1
* @param array $array2
* @return mixed
*/
protected function mergeArrays(array $array1, array $array2)
{
$result = Arr::mergeRecursive($array1, $array2);

foreach ($result as $key => $value) {
if (is_array($value)) {
if (!Arr::isAssociativeArray($value)) {
$result[$key] = $array2[$key];
} else {
$result[$key] = $this->mergeArrays($value, $array2[$key]);
}
}
}

return $result;
}
}
9 changes: 9 additions & 0 deletions src/Utils/Helpers/Arr.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,13 @@ public static function toArrayObject(array $items, bool $unique = true)

return $instance;
}

public static function isAssociativeArray($array)
{
// Used in Laravel. It doesn't work with array like [0 => 1, 2 = 2]
/*$keys = array_keys($array);
return array_keys($keys) !== $keys;*/

return count(array_filter(array_keys($array), 'is_string')) > 0;
}
}
72 changes: 72 additions & 0 deletions test/functional/Infrastructure/Mappers/SimpleSymfonyMapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Clean\Common\Utils\Extensions\ArrayObject\ArrayObjectItem;
use Clean\Common\Utils\Extensions\DateTime;
use test\functional\Infrastructure\TestClasses\Inner;
use test\functional\Infrastructure\TestClasses\InnerDto;
use test\functional\Infrastructure\TestClasses\Outer;
use test\functional\Infrastructure\TestClasses\OuterDto;
use Laminas\ServiceManager\ServiceManager;
Expand Down Expand Up @@ -331,6 +332,77 @@ public function testToObjectWithParameter()
$this->assertEquals('world', $result->getInner()->getName());
}

public function testToObjectWithArrayParameter()
{
$outer = new OuterDto();
$outer->id = 1;
$inner = new InnerDto();
$inner->id = 2;
$inner->items = [
'hello',
'world',
];
$outer->innerDto = $inner;

$array = [
'id' => 1,
'innerDto' => [
'id' => 2,
'items' => [
'hello'
]
]
];

$mapper = $this->getMapper();

$result = $mapper->mapFromArray($array, $outer);

$this->assertEquals(['hello'], $result->innerDto->items);
}

public function testNullableFields()
{
$object = new class() extends \stdClass
{
public int $id;

public ?string $something;
};

$data = ['id' => 1];

$mapper = $this->getMapper();

$result = $mapper->map($data, get_class($object));

$reflection = new \ReflectionProperty($result, 'something');

$this->assertFalse($reflection->isInitialized($result));
}

public function testMapArrayItems()
{
$object = new class() extends \stdClass
{
public int $id;

public array $items;
};
$object->items = ['one', 'two'];

$data = [
'id' => 1,
'items' => ['one'],
];

$mapper = $this->getMapper();

$result = $mapper->map($data, get_class($object));

$this->assertEquals(['one'], $result->items);
}

/**
* @return MapperInterface
* @throws \Psr\Container\ContainerExceptionInterface
Expand Down
2 changes: 2 additions & 0 deletions test/functional/Infrastructure/TestClasses/InnerDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ class InnerDto
public int $id;

public string $name;

public array $items;
}
45 changes: 45 additions & 0 deletions test/unit/Utils/Helpers/ArrTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace unit\Utils\Helpers;

use Clean\Common\Utils\Helpers\Arr;
use PHPUnit\Framework\TestCase;

class ArrTest extends TestCase
{
public function testIsAssociativeTrue()
{
$array = [
'hello' => 'world',
'test' => 1
];

$result = Arr::isAssociativeArray($array);

$this->assertTrue($result);
}

public function testIsAssociativeFalse()
{
$array = [
'hello',
'world'
];

$result = Arr::isAssociativeArray($array);

$this->assertFalse($result);
}

public function testIsAssociativeFalseNotOrdered()
{
$array = [
0 => 'hello',
2 => 'world'
];

$result = Arr::isAssociativeArray($array);

$this->assertFalse($result);
}
}

0 comments on commit a702db9

Please sign in to comment.