Further work on Loz’ solution

This commit is contained in:
Sam Minnee 2017-06-29 11:17:27 +12:00 committed by Guy Sartorelli
parent 850482138b
commit 9c7ecb1f79
No known key found for this signature in database
GPG Key ID: F313E3B9504D496A
3 changed files with 22 additions and 62 deletions

View File

@ -33,7 +33,7 @@ use LogicException;
* *
* Subclasses of DataList may add other methods that have the same effect. * Subclasses of DataList may add other methods that have the same effect.
*/ */
class DataList extends ViewableData implements SS_List, Filterable, Sortable, Limitable, TemplateIterator class DataList extends ViewableData implements SS_List, Filterable, Sortable, Limitable
{ {
/** /**
@ -883,30 +883,13 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
} }
} }
/**
* @return Generator|DataObject[]
*/
public function getTemplateIterator()
{
foreach ($this->getFinalisedQuery() as $row) {
yield $this->createDataObject($row);
}
}
/**
* @return int
*/
public function getTemplateIteratorCount()
{
return $this->getFinalisedQuery()->numRecords();
}
/** /**
* Returns the Query result for this DataList. Repeated calls will return * Returns the Query result for this DataList. Repeated calls will return
* a cached result, unless the DataQuery underlying this list has been * a cached result, unless the DataQuery underlying this list has been
* modified * modified
* *
* @return SilverStripe\ORM\Connect\Query * @return SilverStripe\ORM\Connect\Query
* @internal This API may change in minor releases
*/ */
protected function getFinalisedQuery() protected function getFinalisedQuery()
{ {

View File

@ -290,26 +290,27 @@ class SSViewer_Scope
} }
if (!$this->itemIterator) { if (!$this->itemIterator) {
// TemplateIterator provides methods for extracting the count and iterator directly // Note: it is important that getIterator() is called before count() as implemenations may rely on
if ($this->item instanceof TemplateIterator) { // this to efficiency get both the number of records and an iterator (e.g. DataList does this)
$this->itemIterator = $this->item->getTemplateIterator();
$this->itemIteratorTotal = $this->item->getTemplateIteratorCount();
} else {
// Item may be an array or a regular IteratorAggregate
if (is_array($this->item)) {
$this->itemIterator = new ArrayIterator($this->item);
} else {
$this->itemIterator = $this->item->getIterator();
}
// If the item implements Countable, use that to fetch the count, otherwise we have to inspect the // Item may be an array or a regular IteratorAggregate
// iterator and then rewind it if (is_array($this->item)) {
if ($this->item instanceof Countable) { $this->itemIterator = new ArrayIterator($this->item);
$this->itemIteratorTotal = count($this->item); } else {
} else { $this->itemIterator = $this->item->getIterator();
$this->itemIteratorTotal = iterator_count($this->itemIterator);
$this->itemIterator->rewind(); // This will execute code in a generator up to the first yield. For example, this ensures that
} // DataList::getIterator() is called before Datalist::count()
$this->itemIterator->rewind();
}
// If the item implements Countable, use that to fetch the count, otherwise we have to inspect the
// iterator and then rewind it.
if ($this->item instanceof Countable) {
$this->itemIteratorTotal = count($this->item);
} else {
$this->itemIteratorTotal = iterator_count($this->itemIterator);
$this->itemIterator->rewind();
} }
$this->itemStack[$this->localIndex][SSViewer_Scope::ITEM_ITERATOR] = $this->itemIterator; $this->itemStack[$this->localIndex][SSViewer_Scope::ITEM_ITERATOR] = $this->itemIterator;

View File

@ -1,24 +0,0 @@
<?php
namespace SilverStripe\View;
use IteratorAggregate;
/**
* A special iterator type used by the template engine. The template engine
* needs to know the total number of items before iterating (to save rewinding
* database queries), which is impossible with a natural Generator, so this
* interface allows implementors to pre-compute the total number of items
*/
interface TemplateIterator extends IteratorAggregate
{
/**
* @return Iterator|Generator
*/
public function getTemplateIterator();
/**
* @return int
*/
public function getTemplateIteratorCount();
}