Skip to content

Commit c7b7f53

Browse files
committed
Adding Collection::compile as a way to optimize operations with a single
collection
1 parent 53a2046 commit c7b7f53

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

Cake/Collection/CollectionTrait.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,4 +649,40 @@ public function jsonSerialize() {
649649
return $this->toArray();
650650
}
651651

652+
/**
653+
* Iterates once all elements in this collection and executes all stacked
654+
* operations of them, finally it returns a new collection with the result.
655+
* This is useful for converting non-rewindable internal iterators into
656+
* a collection that can be rewound and used multiple times.
657+
*
658+
* A common use case is to re-use the same variable for calculating different
659+
* data. In those cases it may be helpful and more performant to first compile
660+
* a collection and then apply more operations to it.
661+
*
662+
* ### Example:
663+
*
664+
* {{{
665+
* $collection->map($mapper)->sortBy('age')->extract('name');
666+
* $compiled = $collection->compile();
667+
* $isJohnHere = $compiled->some($johnMatcher);
668+
* $allButJohn = $compiled->filter($johnMatcher);
669+
* }}}
670+
*
671+
* In the above example, had not the collection compiled before, the iterations
672+
* for `map`, `sortBy` and `extract` would've been executed twice: once for
673+
* getting `$isJohnHere` and once for `$allButJohn`
674+
*
675+
* You can think of this method as a way to create save points for complex
676+
* calculations in a collection.
677+
*
678+
* @param boolean $preserveKeys whether to use the keys returned by this
679+
* collection as the array keys. Keep in mind that it is valid for iterators
680+
* to return the same key for different elements, setting this value to false
681+
* can help getting all items if keys are not important in the result.
682+
* @return \Cake\Collection\Collection
683+
*/
684+
public function compile($preserveKeys = true) {
685+
return new Collection($this->toArray($preserveKeys));
686+
}
687+
652688
}

Cake/Test/TestCase/Collection/CollectionTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,4 +604,31 @@ public function testAppend() {
604604
$this->assertEquals(['a' => 4, 'b' => 2, 'c' => 3], $combined->toArray());
605605
}
606606

607+
/**
608+
* Tests that by calling compile internal iteration operations are not done
609+
* more than once
610+
*
611+
* @return void
612+
*/
613+
public function testCompile() {
614+
$items = ['a' => 1, 'b' => 2, 'c' => 3];
615+
$collection = new Collection($items);
616+
$callable = $this->getMock('stdClass', ['__invoke']);
617+
$callable->expects($this->at(0))
618+
->method('__invoke')
619+
->with(1, 'a')
620+
->will($this->returnValue(4));
621+
$callable->expects($this->at(1))
622+
->method('__invoke')
623+
->with(2, 'b')
624+
->will($this->returnValue(5));
625+
$callable->expects($this->at(2))
626+
->method('__invoke')
627+
->with(3, 'c')
628+
->will($this->returnValue(6));
629+
$compiled = $collection->map($callable)->compile();
630+
$this->assertEquals(['a' => 4, 'b' => 5, 'c' => 6], $compiled->toArray());
631+
$this->assertEquals(['a' => 4, 'b' => 5, 'c' => 6], $compiled->toArray());
632+
}
633+
607634
}

0 commit comments

Comments
 (0)