Skip to content

Commit 35ef1d9

Browse files
committed
PipeSelector added, testing in progress.
1 parent 4f166e5 commit 35ef1d9

File tree

6 files changed

+463
-2
lines changed

6 files changed

+463
-2
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ $view[new MaskSelector([true, false, true, false, true])] = [10, 30, 50];
8989
print_r($originalArray); // [10, 2, 30, 4, 50]
9090
```
9191

92-
### Combining subviews
92+
### Combining Subviews
9393
```php
9494
use Smoren\ArrayView\Selectors\IndexListSelector;
9595
use Smoren\ArrayView\Selectors\MaskSelector;
@@ -117,6 +117,29 @@ $subview[':'] = [55, 77];
117117
print_r($originalArray); // [1, 2, 3, 4, 55, 6, 77, 8, 9, 10]
118118
```
119119

120+
### Selectors Pipe
121+
```php
122+
use Smoren\ArrayView\Selectors\IndexListSelector;
123+
use Smoren\ArrayView\Selectors\MaskSelector;
124+
use Smoren\ArrayView\Selectors\SliceSelector;
125+
use Smoren\ArrayView\Views\ArrayView;
126+
127+
$originalArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
128+
$selector = new PipeSelector([
129+
new SliceSelector('::2'),
130+
new MaskSelector([true, false, true, true, true]),
131+
new IndexListSelector([0, 1, 2]),
132+
new SliceSelector('1:'),
133+
]);
134+
135+
$view = ArrayView::toView($originalArray);
136+
$subview = $view->subview($selector);
137+
print_r($subview[':']); // [5, 7]
138+
139+
$subview[':'] = [55, 77];
140+
print_r($originalArray); // [1, 2, 3, 4, 55, 6, 77, 8, 9, 10]
141+
```
142+
120143
## Documentation
121144
For detailed documentation and usage examples, please refer to the
122145
[API documentation](https://smoren.github.io/array-view-php/packages/Application.html).
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Smoren\ArrayView\Interfaces;
6+
7+
/**
8+
* Interface for selector that applies a series of selectors sequentially to a source array view.
9+
*/
10+
interface PipeSelectorInterface extends ArraySelectorInterface
11+
{
12+
/**
13+
* Returns the array of selectors assigned to the PipeSelector.
14+
*
15+
* @return array<ArraySelectorInterface>
16+
*/
17+
public function getValue(): array;
18+
}

src/Selectors/PipeSelector.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Smoren\ArrayView\Selectors;
6+
7+
use Smoren\ArrayView\Interfaces\ArraySelectorInterface;
8+
use Smoren\ArrayView\Interfaces\ArrayViewInterface;
9+
use Smoren\ArrayView\Interfaces\PipeSelectorInterface;
10+
use Smoren\ArrayView\Views\ArrayView;
11+
12+
/**
13+
* Represents a selector that applies a series of selectors sequentially to a source array view.
14+
*
15+
* ##### Example
16+
* ```php
17+
* $originalArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
18+
* $selector = new PipeSelector([
19+
* new SliceSelector('::2'),
20+
* new MaskSelector([true, false, true, true, true]),
21+
* new IndexListSelector([0, 1, 2]),
22+
* new SliceSelector('1:'),
23+
* ]);
24+
*
25+
* $view = ArrayView::toView($originalArray);
26+
* $subview = $view->subview($selector);
27+
* print_r($subview[':']); // [5, 7]
28+
*
29+
* $subview[':'] = [55, 77];
30+
* print_r($originalArray); // [1, 2, 3, 4, 55, 6, 77, 8, 9, 10]
31+
* ```
32+
*/
33+
class PipeSelector implements PipeSelectorInterface
34+
{
35+
/**
36+
* @var array<ArraySelectorInterface> An array of selectors to be applied sequentially.
37+
*/
38+
private array $selectors;
39+
40+
/**
41+
* Creates a new PipeSelector instance with the provided selectors array.
42+
*
43+
* @param array<ArraySelectorInterface> $selectors An array of selectors to be assigned to the PipeSelector.
44+
*/
45+
public function __construct(array $selectors)
46+
{
47+
$this->selectors = $selectors;
48+
}
49+
50+
/**
51+
* Applies the series of selectors to the given source array view.
52+
*
53+
* @template T The type of elements in the source array view.
54+
*
55+
* @param ArrayViewInterface<T> $source The source array view to select from.
56+
* @param bool|null $readonly Optional parameter to specify if the view should be read-only.
57+
*
58+
* @return ArrayViewInterface<T> The resulting array view after applying all selectors.
59+
*/
60+
public function select(ArrayViewInterface $source, ?bool $readonly = null): ArrayViewInterface
61+
{
62+
$view = ArrayView::toView($source, $readonly);
63+
foreach ($this->selectors as $selector) {
64+
$view = $selector->select($view, $readonly);
65+
}
66+
/** @var ArrayViewInterface<T> $view */
67+
return $view;
68+
}
69+
70+
/**
71+
* Checks if the series of selectors are compatible with the given array view.
72+
*
73+
* @template T The type of elements in the source array view.
74+
*
75+
* @param ArrayViewInterface<T> $view The array view to check compatibility with.
76+
*
77+
* @return bool True if all selectors are compatible with the array view, false otherwise.
78+
*/
79+
public function compatibleWith(ArrayViewInterface $view): bool
80+
{
81+
foreach ($this->selectors as $selector) {
82+
if (!$selector->compatibleWith($view)) {
83+
return false;
84+
}
85+
$view = $selector->select($view);
86+
}
87+
return true;
88+
}
89+
90+
/**
91+
* Returns the array of selectors assigned to the PipeSelector.
92+
*
93+
* @return array<ArraySelectorInterface> The array of selectors.
94+
*/
95+
public function getValue(): array
96+
{
97+
return $this->selectors;
98+
}
99+
}

tests/unit/ArrayView/ReadTest.php

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

55
use Smoren\ArrayView\Selectors\IndexListSelector;
66
use Smoren\ArrayView\Selectors\MaskSelector;
7+
use Smoren\ArrayView\Selectors\PipeSelector;
78
use Smoren\ArrayView\Selectors\SliceSelector;
89
use Smoren\ArrayView\Views\ArrayIndexListView;
910
use Smoren\ArrayView\Views\ArrayMaskView;
@@ -42,6 +43,21 @@ public function testReadCombined(array $source, callable $viewGetter, array $exp
4243
$this->assertSame($view->toArray(), $expected);
4344
}
4445

46+
/**
47+
* @dataProvider dataProviderForReadPipe
48+
*/
49+
public function testReadPipe(array $source, array $selectors, array $expected)
50+
{
51+
$view = ArrayView::toView($source);
52+
$selector = new PipeSelector($selectors);
53+
54+
$subview = $view->subview($selector);
55+
$subArray = $view[$selector];
56+
57+
$this->assertSame($subview->toArray(), $expected);
58+
$this->assertSame($subArray, $expected);
59+
}
60+
4561
/**
4662
* @dataProvider dataProviderForIsAndFilter
4763
*/
@@ -190,6 +206,148 @@ public function dataProviderForReadCombine(): array
190206
->subview('1:'),
191207
[9],
192208
],
209+
[
210+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
211+
fn (array &$source) => ArrayView::toView($source)
212+
->subview(new PipeSelector([
213+
new SliceSelector('::2'),
214+
new MaskSelector([true, false, true, false, true]),
215+
]))
216+
->subview(new IndexListSelector([0, 2])),
217+
[1, 9],
218+
],
219+
[
220+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
221+
fn (array &$source) => ArrayView::toView($source)
222+
->subview(new SliceSelector('::2'))
223+
->subview(new PipeSelector([
224+
new MaskSelector([true, false, true, false, true]),
225+
]))
226+
->subview(new IndexListSelector([0, 2])),
227+
[1, 9],
228+
],
229+
[
230+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
231+
fn (array &$source) => ArrayView::toView($source)
232+
->subview(new SliceSelector('::2'))
233+
->subview(new PipeSelector([
234+
new MaskSelector([true, false, true, false, true]),
235+
new IndexListSelector([0, 2])
236+
])),
237+
[1, 9],
238+
],
239+
];
240+
}
241+
242+
public function dataProviderForReadPipe(): array
243+
{
244+
return [
245+
[
246+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
247+
[new SliceSelector('::2')],
248+
[1, 3, 5, 7, 9],
249+
],
250+
[
251+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
252+
[new SliceSelector('::2')],
253+
[1, 3, 5, 7, 9],
254+
],
255+
[
256+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
257+
[new SliceSelector('::2')],
258+
[1, 3, 5, 7, 9],
259+
],
260+
[
261+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
262+
[
263+
new MaskSelector([true, true, true, true, true, true, true, true, true, true]),
264+
new SliceSelector('::2'),
265+
],
266+
[1, 3, 5, 7, 9],
267+
],
268+
[
269+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
270+
[
271+
new SliceSelector('::1'),
272+
new SliceSelector('::2'),
273+
],
274+
[1, 3, 5, 7, 9],
275+
],
276+
[
277+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
278+
[
279+
new SliceSelector('::2'),
280+
new MaskSelector([true, false, true, false, true]),
281+
],
282+
[1, 5, 9],
283+
],
284+
[
285+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
286+
[
287+
new SliceSelector('::2'),
288+
new MaskSelector([true, false, true, false, true]),
289+
new IndexListSelector([0, 2]),
290+
],
291+
[1, 9],
292+
],
293+
[
294+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
295+
[
296+
new SliceSelector('::2'),
297+
new MaskSelector([true, false, true, false, true]),
298+
new IndexListSelector([0, 2]),
299+
new SliceSelector('1:'),
300+
],
301+
[9],
302+
],
303+
[
304+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
305+
[
306+
new MaskSelector([true, false, true, false, true, false, true, false, true, false]),
307+
new MaskSelector([true, false, true, false, true]),
308+
new MaskSelector([true, false, true]),
309+
new MaskSelector([false, true]),
310+
],
311+
[9],
312+
],
313+
[
314+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
315+
[
316+
new MaskSelector([true, false, true, false, true, false, true, false, true, false]),
317+
new MaskSelector([true, false, true, false, true]),
318+
new MaskSelector([true, false, true]),
319+
],
320+
[1, 9],
321+
],
322+
[
323+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
324+
[
325+
new IndexListSelector([0, 2, 4, 6, 8]),
326+
new IndexListSelector([0, 2, 4]),
327+
new IndexListSelector([0, 2]),
328+
new IndexListSelector([1]),
329+
],
330+
[9],
331+
],
332+
[
333+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
334+
[
335+
new SliceSelector('::2'),
336+
new SliceSelector('::2'),
337+
new SliceSelector('::2'),
338+
],
339+
[1, 9],
340+
],
341+
[
342+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
343+
[
344+
new SliceSelector('::2'),
345+
new SliceSelector('::2'),
346+
new SliceSelector('::2'),
347+
new SliceSelector('1:'),
348+
],
349+
[9],
350+
],
193351
];
194352
}
195353

0 commit comments

Comments
 (0)