Skip to content

Commit 9eeb107

Browse files
committed
Throw exception when unflattening with empty separator. Add Flatten::flattenToArray function.
1 parent 89823ab commit 9eeb107

File tree

4 files changed

+67
-55
lines changed

4 files changed

+67
-55
lines changed

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ Flatten::__construct(
3535
*/
3636
$flatten = new Flatten();
3737

38-
$flattened = $flatten->flatten($multiArray);
39-
38+
// Flatten::flattenToArray is provided for convinience. It internally
39+
// calls Flatten::flatten and converts it's output, which is a 1-dimensional
40+
// iterator, into a 1-dimensional array.
41+
$flattened = $flatten->flattenToArray($multiArray);
4042

4143
// Flatten::unflattenToArray is provided for convinience. It internally
4244
// calls Flatten::unflatten and converts it's output, which is a recursive
@@ -70,7 +72,7 @@ $flatten = new Flatten(
7072
'/' // prefix
7173
);
7274

73-
$flattened = $flatten->flatten($allowAccess);
75+
$flattened = $flatten->flattenToArray($allowAccess);
7476

7577
$unflattened = $flatten->unflattenToArray($flattened);
7678

@@ -100,7 +102,7 @@ $api = [
100102

101103
$flatten = new Flatten('/', 'https://api.dummyhost.domain/');
102104

103-
$flattened = $flatten->flatten($api);
105+
$flattened = $flatten->flattenToArray($api);
104106

105107
$unflattened = $flatten->unflattenToArray($flattened);
106108

@@ -135,7 +137,7 @@ $nutrition = [
135137

136138
$flatten = new Flatten('-');
137139

138-
$flattened = $flatten->flatten($nutrition);
140+
$flattened = $flatten->flattenToArray($nutrition);
139141

140142
$unflattened = $flatten->unflattenToArray($flattened);
141143

@@ -178,7 +180,7 @@ $flatten = new Flatten(
178180
Flatten::FLAG_NUMERIC_NOT_FLATTENED
179181
);
180182

181-
$flattened = $flatten->flatten($examples);
183+
$flattened = $flatten->flattenToArray($examples);
182184

183185
$unflattened = $flatten->unflattenToArray($flattened);
184186

@@ -223,7 +225,7 @@ $flatten = new Flatten(
223225
Flatten::FLAG_NUMERIC_NOT_FLATTENED
224226
);
225227

226-
$flattened = $flatten->flatten($seats);
228+
$flattened = $flatten->flattenToArray($seats);
227229

228230
$unflattened = $flatten->unflattenToArray($flattened);
229231

src/EmptySeparatorException.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Sarhan\Flatten;
4+
5+
class EmptySeparatorException extends \Exception
6+
{
7+
public function __construct()
8+
{
9+
parent::__construct('Cannot unflatten with an empty separator');
10+
}
11+
}

src/Flatten.php

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class Flatten
1515

1616
/**
1717
* Turn off flattening values with integer keys.
18+
*
19+
* This flag has no effect on unflattening (the reverse function).
1820
*/
1921
const FLAG_NUMERIC_NOT_FLATTENED = 0b1;
2022

@@ -68,10 +70,22 @@ public function flatten($var)
6870
}
6971
}
7072

73+
/**
74+
* Flattens an iterable into a 1-dimensional array.
75+
*
76+
* @param mixed $var
77+
* @return array
78+
* @see flatten
79+
*/
80+
public function flattenToArray($var)
81+
{
82+
return iterator_to_array($this->flatten($var));
83+
}
84+
7185
/**
7286
* Unflattens a 1-dimensional iterable into a multi-dimensional generator.
7387
*
74-
* Fully Qualitifed Keys (FQks) in the input array will be split by the
88+
* Fully Qualitifed Keys (FQKs) in the input array will be split by the
7589
* configured separator, and resulting splits will form keys for each level
7690
* down the resulting multi-dimensional array.
7791
*
@@ -86,9 +100,14 @@ public function flatten($var)
86100
* @return multi-dimensional generator.
87101
* @see Util\TraversableToArray
88102
* @see unflattenToArray
103+
* @throws EmptySeparatorException when the configured separator is empty
89104
*/
90105
public function unflatten($var)
91106
{
107+
if (empty($this->separator)) {
108+
throw new EmptySeparatorException();
109+
}
110+
92111
if (!$this->canTraverse($var)) {
93112
yield $var;
94113
}
@@ -97,17 +116,15 @@ public function unflatten($var)
97116
$key = substr($key, strlen($this->prefix));
98117

99118
if (!empty($key)) {
100-
foreach ($this->unflattenGenerator($key, $value) as $k => $v) {
119+
$value = $this->unflattenGenerator($key, $value);
120+
}
121+
122+
if ($this->canTraverse($value)) {
123+
foreach ($value as $k => $v) {
101124
yield $k => $v;
102125
}
103126
} else {
104-
if ($this->canTraverse($value)) {
105-
foreach ($value as $k => $v) {
106-
yield $k => $v;
107-
}
108-
} else {
109-
yield $value;
110-
}
127+
yield $value;
111128
}
112129
}
113130
}
@@ -117,7 +134,7 @@ public function unflatten($var)
117134
*
118135
* @param mixed $var
119136
* @return array
120-
* @see flatten
137+
* @see unflatten
121138
*/
122139
public function unflattenToArray($var)
123140
{
@@ -159,15 +176,13 @@ private function unflattenGenerator($fqk, $value)
159176

160177
private function splitFQK($fqk)
161178
{
162-
$res = !empty($this->separator)
163-
? explode($this->separator, $fqk, 2)
164-
: [substr($fqk, 0, 1), substr($fqk, 1)];
179+
$splits = explode($this->separator, $fqk, 2);
165180

166-
if (!isset($res[1])) {
167-
$res[1] = null;
181+
if (!isset($splits[1])) {
182+
$splits[1] = null;
168183
}
169184

170-
return $res;
185+
return $splits;
171186
}
172187

173188
private function canTraverse($var)

test/UnflattenTest.php

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PHPUnit\Framework\TestCase;
66
use Sarhan\Flatten\Flatten;
7+
use Sarhan\Flatten\EmptySeparatorException;
78
use Sarhan\Flatten\Util\TraversableToArray;
89

910
class UnflattenTest extends TestCase
@@ -27,7 +28,6 @@ public function scalarOutputProvider()
2728
public function testUnflattenScalar($input, $expectedOutput)
2829
{
2930
$output = $this->unflattenToArray($input);
30-
3131
$this->assertEquals($expectedOutput, $output);
3232
}
3333

@@ -50,7 +50,6 @@ public function scalarOutputSeparatorPrefixProvider()
5050
public function testUnflattenScalarWithSeparatorAndPrefix($input, $separator, $prefix, $expectedOutput)
5151
{
5252
$output = $this->unflattenToArray($input, $separator, $prefix);
53-
5453
$this->assertEquals($expectedOutput, $output);
5554
}
5655

@@ -82,7 +81,6 @@ public function arraysProvider()
8281
public function testUnflattenArrays($input, $expectedOutput)
8382
{
8483
$output = $this->unflattenToArray($input);
85-
8684
$this->assertEquals($expectedOutput, $output);
8785
}
8886

@@ -140,39 +138,22 @@ public function traversablesSeparatorPrefixProvider()
140138
[ 'a' => 1, 2, 'b' => [ 3, 'c' => 4 ] ]
141139
],
142140
[
143-
new \ArrayIterator([ ':a' => 1, ':b' => 2, ':cd0' => 3, ':cd1' => 4, ':cef' => 5, ':ceg' => 6 ]),
144-
'',
141+
new \ArrayIterator([ ':a' => 1, ':b' => 2, ':c.d.0' => 3, ':c.d.1' => 4, ':c.e.f' => 5 ]),
142+
'.',
145143
':',
146144
[
147145
'a' => 1,
148146
'b' => 2,
149-
'c' => [ 'd' => [ 3, 4 ], 'e' => [ 'f' => 5, 'g' => 6 ] ]
147+
'c' => [ 'd' => [ 3, 4 ], 'e' => [ 'f' => 5 ] ]
150148
]
151-
]
152-
];
153-
}
154-
155-
/**
156-
* @covers Flatten::unflatten
157-
* @dataProvider traversablesSeparatorPrefixProvider
158-
*/
159-
public function testUnflattenTraversableWithSeparatorAndPrefix($input, $separator, $prefix, $expectedOutput)
160-
{
161-
$output = $this->unflattenToArray($input, $separator, $prefix);
162-
$this->assertEquals($expectedOutput, $output);
163-
}
164-
165-
public function flattenWithFlagsProvidor()
166-
{
167-
return [
149+
],
168150
'NUMERIC_NOT_FLATTENED' => [
169151
[
170152
'_' => [1, 2, 100 => [3, 4]],
171153
'_numericOnly' => ['A', 'B', 'C', 'D'],
172154
],
173155
'.',
174156
'_',
175-
Flatten::FLAG_NUMERIC_NOT_FLATTENED,
176157
[
177158
1,
178159
2,
@@ -192,7 +173,6 @@ public function flattenWithFlagsProvidor()
192173
],
193174
'.',
194175
'_',
195-
Flatten::FLAG_NUMERIC_NOT_FLATTENED,
196176
[
197177
1,
198178
2,
@@ -215,7 +195,6 @@ public function flattenWithFlagsProvidor()
215195
],
216196
'.',
217197
'_',
218-
Flatten::FLAG_NUMERIC_NOT_FLATTENED,
219198
[
220199
'numericOnly' => ['A', 'B', 'C', 'D'],
221200
'mixed' => ['A', 'B', 'digit' => 0],
@@ -228,20 +207,25 @@ public function flattenWithFlagsProvidor()
228207

229208
/**
230209
* @covers Flatten::unflatten
231-
* @dataProvider flattenWithFlagsProvidor
210+
* @dataProvider traversablesSeparatorPrefixProvider
232211
*/
233-
public function testUnflattenWithFlags($input, $separator, $prefix, $flags, $expectedOutput)
212+
public function testUnflattenTraversableWithSeparatorAndPrefix($input, $separator, $prefix, $expectedOutput)
234213
{
235-
$output = $this->unflattenToArray($input, $separator, $prefix, $flags);
214+
$output = $this->unflattenToArray($input, $separator, $prefix);
236215
$this->assertEquals($expectedOutput, $output);
237216
}
238217

218+
public function testUnflattenWithEmptySeparatorConfiguration()
219+
{
220+
$this->expectException(EmptySeparatorException::class);
221+
$this->unflattenToArray(['ab' => 0, 'abc' => 1, 'abd' => 2], '', '');
222+
}
223+
239224
private function unflattenToArray(
240225
$input,
241226
$separator = Flatten::DEFAULT_SEPARATOR,
242-
$prefix = Flatten::DEFAULT_PREFIX,
243-
$flags = Flatten::DEFAULT_FLAGS
227+
$prefix = Flatten::DEFAULT_PREFIX
244228
) {
245-
return (new Flatten($separator, $prefix, $flags))->unflattenToArray($input);
229+
return (new Flatten($separator, $prefix))->unflattenToArray($input);
246230
}
247231
}

0 commit comments

Comments
 (0)