Skip to content

Commit

Permalink
Naïve version of supporting {n} notation in collection methods
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed May 31, 2015
1 parent a340d8b commit 4761d41
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 8 deletions.
13 changes: 11 additions & 2 deletions src/Collection/CollectionTrait.php
Expand Up @@ -158,11 +158,20 @@ public function reduce(callable $c, $zero = null)
/**
* {@inheritDoc}
*
* @return \Cake\Collection\Iterator\ExtractIterator
*/
public function extract($matcher)
{
return new ExtractIterator($this->unwrap(), $matcher);
$extractor = new ExtractIterator($this->unwrap(), $matcher);

if (is_string($matcher) && strpos($matcher, '{n}') !== false) {
$extractor = $extractor
->filter(function ($data) {
return $data instanceof \Traversable || is_array($data);
})
->unfold();
}

return $extractor;
}

/**
Expand Down
32 changes: 26 additions & 6 deletions src/Collection/ExtractTrait.php
Expand Up @@ -32,13 +32,15 @@ trait ExtractTrait
*/
protected function _propertyExtractor($callback)
{
if (is_string($callback)) {
$path = explode('.', $callback);
$callback = function ($element) use ($path) {
return $this->_extract($element, $path);
};
if (!is_string($callback)) {
return $callback;
}

$path = explode('.', $callback);
$callback = function ($element) use ($path) {
return $this->_extract($element, $path);
};

return $callback;
}

Expand All @@ -53,10 +55,28 @@ protected function _propertyExtractor($callback)
protected function _extract($data, $path)
{
$value = null;
foreach ($path as $column) {
$collectionTransform = false;

foreach ($path as $i => $column) {
if ($column === '{n}') {
$collectionTransform = true;
continue;
}

if ($collectionTransform &&
!($data instanceof \Traversable || is_array($data))) {
return null;
}

if ($collectionTransform) {
$rest = implode('.', array_slice($path, $i));
return (new Collection($data))->extract($rest);
}

if (!isset($data[$column])) {
return null;
}

$value = $data[$column];
$data = $value;
}
Expand Down
47 changes: 47 additions & 0 deletions tests/TestCase/Collection/CollectionTest.php
Expand Up @@ -1381,4 +1381,51 @@ public function testSumOfWithIdentity()
$collection = new Collection(['a' => 1, 'b' => 4, 'c' => 6]);
$this->assertEquals(11, $collection->sumOf());
}

public function testUnfoldedExtract()
{
$items = [
['comments' => [['id' => 1], ['id' => 2]]],
['comments' => [['id' => 3], ['id' => 4]]],
['comments' => [['id' => 7], ['nope' => 8]]],
];

$extracted = (new Collection($items))->extract('comments.{n}.id');
$this->assertEquals([1, 2, 3, 4, 7, null], $extracted->toList());

$items = [
[
'comments' => [
[
'voters' => [['id' => 1], ['id' => 2]]
]
]
],
[
'comments' => [
[
'voters' => [['id' => 3], ['id' => 4]]
]
]
],
[
'comments' => [
[
'voters' => [['id' => 5], ['nope' => 'fail'], ['id' => 6]]
]
]
],
[
'comments' => [
[
'not_voters' => [['id' => 5]]
]
]
],
['not_comments' => []]
];
$extracted = (new Collection($items))->extract('comments.{n}.voters.{n}.id');
$expected = [1, 2, 3, 4, 5, null];
$this->assertEquals($expected, $extracted->toList());
}
}

0 comments on commit 4761d41

Please sign in to comment.