Skip to content

Commit 9bef95c

Browse files
authored
Merge pull request #32 from colinodell/merge-modes
Add new MERGE import mode
2 parents 2951b7d + 16388ed commit 9bef95c

File tree

4 files changed

+73
-36
lines changed

4 files changed

+73
-36
lines changed

src/Data.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,17 +178,17 @@ public function getData(string $key): DataInterface
178178
/**
179179
* {@inheritdoc}
180180
*/
181-
public function import(array $data, bool $clobber = true): void
181+
public function import(array $data, int $mode = self::REPLACE): void
182182
{
183-
$this->data = Util::mergeAssocArray($this->data, $data, $clobber);
183+
$this->data = Util::mergeAssocArray($this->data, $data, $mode);
184184
}
185185

186186
/**
187187
* {@inheritdoc}
188188
*/
189-
public function importData(DataInterface $data, bool $clobber = true): void
189+
public function importData(DataInterface $data, int $mode = self::REPLACE): void
190190
{
191-
$this->import($data->export(), $clobber);
191+
$this->import($data->export(), $mode);
192192
}
193193

194194
/**

src/DataInterface.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818

1919
interface DataInterface
2020
{
21+
public const PRESERVE = 0;
22+
public const REPLACE = 1;
23+
public const MERGE = 2;
24+
2125
/**
2226
* Append a value to a key (assumes key refers to an array value)
2327
*
@@ -103,18 +107,18 @@ public function getData(string $key): DataInterface;
103107
/**
104108
* Import data into existing data
105109
*
106-
* @param array<string, mixed> $data
107-
* @param bool $clobber
110+
* @param array<string, mixed> $data
111+
* @param self::PRESERVE|self::REPLACE|self::MERGE $mode
108112
*/
109-
public function import(array $data, bool $clobber = true): void;
113+
public function import(array $data, int $mode = self::REPLACE): void;
110114

111115
/**
112116
* Import data from an external data into existing data
113117
*
114-
* @param DataInterface $data
115-
* @param bool $clobber
118+
* @param DataInterface $data
119+
* @param self::PRESERVE|self::REPLACE|self::MERGE $mode
116120
*/
117-
public function importData(DataInterface $data, bool $clobber = true): void;
121+
public function importData(DataInterface $data, int $mode = self::REPLACE): void;
118122

119123
/**
120124
* Export data as raw data

src/Util.php

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,26 +37,42 @@ public static function isAssoc(array $arr): bool
3737
*
3838
* @param mixed $to
3939
* @param mixed $from
40-
* @param bool $clobber
40+
* @param DataInterface::PRESERVE|DataInterface::REPLACE|DataInterface::MERGE $mode
4141
*
4242
* @return mixed
4343
*
4444
* @psalm-pure
4545
*/
46-
public static function mergeAssocArray($to, $from, $clobber = true)
46+
public static function mergeAssocArray($to, $from, int $mode = DataInterface::REPLACE)
4747
{
48-
if (is_array($from)) {
48+
if ($mode === DataInterface::MERGE && self::isList($to) && self::isList($from)) {
49+
return array_merge($to, $from);
50+
}
51+
52+
if (is_array($from) && is_array($to)) {
4953
foreach ($from as $k => $v) {
5054
if (!isset($to[$k])) {
5155
$to[$k] = $v;
5256
} else {
53-
$to[$k] = self::mergeAssocArray($to[$k], $v, $clobber);
57+
$to[$k] = self::mergeAssocArray($to[$k], $v, $mode);
5458
}
5559
}
5660

5761
return $to;
5862
}
5963

60-
return $clobber ? $from : $to;
64+
return $mode === DataInterface::PRESERVE ? $to : $from;
65+
}
66+
67+
/**
68+
* @param mixed $value
69+
*
70+
* @return bool
71+
*
72+
* @psalm-pure
73+
*/
74+
private static function isList($value): bool
75+
{
76+
return is_array($value) && array_values($value) === $value;
6177
}
6278
}

tests/UtilTest.php

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,59 +27,64 @@ public function testIsAssoc()
2727
/**
2828
* @dataProvider mergeAssocArrayProvider
2929
*/
30-
public function testMergeAssocArray($message, $to, $from, $clobber, $expectedResult)
30+
public function testMergeAssocArray($message, $to, $from, $mode, $expectedResult)
3131
{
32-
$result = Util::mergeAssocArray($to, $from, $clobber);
32+
if ($mode === null) {
33+
$result = Util::mergeAssocArray($to, $from);
34+
} else {
35+
$result = Util::mergeAssocArray($to, $from, $mode);
36+
}
37+
3338
$this->assertEquals($expectedResult, $result, $message);
3439
}
3540

3641
public function mergeAssocArrayProvider()
3742
{
3843
return [
3944
[
40-
'Clobber should replace to value with from value for strings (shallow)',
45+
'Overwrite should replace to value with from value for strings (shallow)',
4146
// to
4247
['a' => 'A'],
4348
// from
4449
['a' => 'B'],
45-
// clobber
46-
true,
50+
// mode
51+
DataInterface::REPLACE,
4752
// expected result
4853
['a' => 'B'],
4954
],
5055

5156
[
52-
'Clobber should replace to value with from value for strings (deep)',
57+
'Overwrite should replace to value with from value for strings (deep)',
5358
// to
5459
['a' => ['b' => 'B']],
5560
// from
5661
['a' => ['b' => 'C']],
57-
// clobber
58-
true,
62+
// mode
63+
DataInterface::REPLACE,
5964
// expected result
6065
['a' => ['b' => 'C']]
6166
],
6267

6368
[
64-
'Clobber should NOTreplace to value with from value for strings (shallow)',
69+
'Existing values are not replaced in preserve mode (shallow)',
6570
// to
6671
['a' => 'A'],
6772
// from
6873
['a' => 'B'],
69-
// clobber
70-
false,
74+
// mode
75+
DataInterface::PRESERVE,
7176
// expected result
7277
['a' => 'A'],
7378
],
7479

7580
[
76-
'Clobber should NOT replace to value with from value for strings (deep)',
81+
'Existing values are not replaced in preserve mode (deep)',
7782
// to
7883
['a' => ['b' => 'B']],
7984
// from
8085
['a' => ['b' => 'C']],
81-
// clobber
82-
false,
86+
// mode
87+
DataInterface::PRESERVE,
8388
// expected result
8489
['a' => ['b' => 'B']],
8590
],
@@ -90,35 +95,47 @@ public function mergeAssocArrayProvider()
9095
['a' => ['b' => 'B']],
9196
// from
9297
['a' => ['c' => 'C']],
93-
// clobber
98+
// mode
9499
null,
95100
// expected result
96101
['a' => ['b' => 'B', 'c' => 'C']],
97102
],
98103

99104
[
100-
'Arrays should be replaced (with clobber enabled)',
105+
'Arrays should be replaced',
101106
// to
102107
['a' => ['b', 'c']],
103108
// from
104109
['a' => ['B', 'C']],
105-
// clobber
106-
true,
110+
// mode
111+
DataInterface::REPLACE,
107112
// expected result
108113
['a' => ['B', 'C']],
109114
],
110115

111116
[
112-
'Arrays should be NOT replaced (with clobber disabled)',
117+
'Arrays should be preserved',
113118
// to
114119
['a' => ['b', 'c']],
115120
// from
116121
['a' => ['B', 'C']],
117-
// clobber
118-
false,
122+
// mode
123+
DataInterface::PRESERVE,
119124
// expected result
120125
['a' => ['b', 'c']],
121126
],
127+
128+
[
129+
'Arrays should be merged/appended (when using MERGE)',
130+
// to
131+
['a' => 1, 'b' => 1, 'n' => [1], 'x' => 'string', 'y' => ['stringindex' => 1]],
132+
// from
133+
['a' => 2, 'c' => 2, 'n' => [2], 'x' => ['array'], 'y' => [2]],
134+
// mode
135+
DataInterface::MERGE,
136+
// expected result
137+
['a' => 2, 'b' => 1, 'c' => 2, 'n' => [1, 2], 'x' => ['array'], 'y' => ['stringindex' => 1, 0 => 2]]
138+
],
122139
];
123140
}
124141
}

0 commit comments

Comments
 (0)