From 6ef5785fc5338eac1213af8feddf9f407e7ff43f Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Wed, 18 Jan 2017 09:24:12 +1300 Subject: [PATCH] FIX: pre-cache loop content within SSViewer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SSViewer iterates on Iterators that it receives twice: first to get the total number of items, then to actually render each item. This necessitates a rewind. In order to make more use of generators, which are not rewindable, I’d like to remove the need for a rewind. I’ve done this by caching the content of the iterator as an array within SSViewer_Scope. Although this means a bit of memory usage, there are no cases in which code will get to this point without iterating on all items, which would use the memory anyway. It would only create onerous impacts in cases where you are iterating on very long iterators, which would mean you’re rendering a very large page anyway, and probably have other performance issues. --- src/View/SSViewer_Scope.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/View/SSViewer_Scope.php b/src/View/SSViewer_Scope.php index 224fd0753..69a4c4cd4 100644 --- a/src/View/SSViewer_Scope.php +++ b/src/View/SSViewer_Scope.php @@ -289,14 +289,20 @@ class SSViewer_Scope } if (!$this->itemIterator) { + // Turn the iterator into an array. This lets us get the count and iterate on it, even if it's a generator. if (is_array($this->item)) { - $this->itemIterator = new ArrayIterator($this->item); + $arrayVersion = $this->item; } else { - $this->itemIterator = $this->item->getIterator(); + $arrayVersion = []; + foreach ($this->item as $record) { + $arrayVersion[] = $record; + } } + $this->itemIterator = new ArrayIterator($arrayVersion); + $this->itemStack[$this->localIndex][SSViewer_Scope::ITEM_ITERATOR] = $this->itemIterator; - $this->itemIteratorTotal = iterator_count($this->itemIterator); // Count the total number of items + $this->itemIteratorTotal = count($arrayVersion); // Count the total number of items $this->itemStack[$this->localIndex][SSViewer_Scope::ITEM_ITERATOR_TOTAL] = $this->itemIteratorTotal; $this->itemIterator->rewind(); } else {