mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Proposed solution for caching template generator counts
This commit is contained in:
parent
8e0e797b40
commit
850482138b
@ -6,6 +6,7 @@ use SilverStripe\Core\Injector\Injector;
|
|||||||
use SilverStripe\Dev\Debug;
|
use SilverStripe\Dev\Debug;
|
||||||
use SilverStripe\ORM\Filters\SearchFilter;
|
use SilverStripe\ORM\Filters\SearchFilter;
|
||||||
use SilverStripe\ORM\Queries\SQLConditionGroup;
|
use SilverStripe\ORM\Queries\SQLConditionGroup;
|
||||||
|
use SilverStripe\View\TemplateIterator;
|
||||||
use SilverStripe\View\ViewableData;
|
use SilverStripe\View\ViewableData;
|
||||||
use ArrayIterator;
|
use ArrayIterator;
|
||||||
use Exception;
|
use Exception;
|
||||||
@ -32,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
|
class DataList extends ViewableData implements SS_List, Filterable, Sortable, Limitable, TemplateIterator
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,6 +50,13 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||||||
*/
|
*/
|
||||||
protected $dataQuery;
|
protected $dataQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cached Query to save repeated database calls. {@see DataList::getTemplateIteratorCount()}
|
||||||
|
*
|
||||||
|
* @var SilverStripe\ORM\Connect\Query
|
||||||
|
*/
|
||||||
|
protected $finalisedQuery;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new DataList.
|
* Create a new DataList.
|
||||||
* No querying is done on construction, but the initial query schema is set up.
|
* No querying is done on construction, but the initial query schema is set up.
|
||||||
@ -79,6 +87,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||||||
public function __clone()
|
public function __clone()
|
||||||
{
|
{
|
||||||
$this->dataQuery = clone $this->dataQuery;
|
$this->dataQuery = clone $this->dataQuery;
|
||||||
|
$this->finalisedQuery = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -869,11 +878,45 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||||||
#[\ReturnTypeWillChange]
|
#[\ReturnTypeWillChange]
|
||||||
public function getIterator()
|
public function getIterator()
|
||||||
{
|
{
|
||||||
foreach ($this->dataQuery->query()->execute() as $row) {
|
foreach ($this->getFinalisedQuery() as $row) {
|
||||||
yield $this->createDataObject($row);
|
yield $this->createDataObject($row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
* a cached result, unless the DataQuery underlying this list has been
|
||||||
|
* modified
|
||||||
|
*
|
||||||
|
* @return SilverStripe\ORM\Connect\Query
|
||||||
|
*/
|
||||||
|
protected function getFinalisedQuery()
|
||||||
|
{
|
||||||
|
if (!$this->finalisedQuery) {
|
||||||
|
$this->finalisedQuery = $this->dataQuery->query()->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->finalisedQuery;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the number of items in this DataList
|
* Return the number of items in this DataList
|
||||||
*
|
*
|
||||||
@ -882,6 +925,10 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||||||
#[\ReturnTypeWillChange]
|
#[\ReturnTypeWillChange]
|
||||||
public function count()
|
public function count()
|
||||||
{
|
{
|
||||||
|
if ($this->finalisedQuery) {
|
||||||
|
return $this->finalisedQuery->numRecords();
|
||||||
|
}
|
||||||
|
|
||||||
return $this->dataQuery->count();
|
return $this->dataQuery->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1029,6 +1076,11 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||||||
*/
|
*/
|
||||||
public function column($colName = "ID")
|
public function column($colName = "ID")
|
||||||
{
|
{
|
||||||
|
if ($this->finalisedQuery) {
|
||||||
|
$finalisedQuery = clone $this->finalisedQuery;
|
||||||
|
return $finalisedQuery->distinct(false)->column($colName);
|
||||||
|
}
|
||||||
|
|
||||||
$dataQuery = clone $this->dataQuery;
|
$dataQuery = clone $this->dataQuery;
|
||||||
return $dataQuery->distinct(false)->column($colName);
|
return $dataQuery->distinct(false)->column($colName);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace SilverStripe\View;
|
namespace SilverStripe\View;
|
||||||
|
|
||||||
use ArrayIterator;
|
use ArrayIterator;
|
||||||
|
use Countable;
|
||||||
use Iterator;
|
use Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -289,22 +290,30 @@ class SSViewer_Scope
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->itemIterator) {
|
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.
|
// TemplateIterator provides methods for extracting the count and iterator directly
|
||||||
if (is_array($this->item)) {
|
if ($this->item instanceof TemplateIterator) {
|
||||||
$arrayVersion = $this->item;
|
$this->itemIterator = $this->item->getTemplateIterator();
|
||||||
|
$this->itemIteratorTotal = $this->item->getTemplateIteratorCount();
|
||||||
} else {
|
} else {
|
||||||
$arrayVersion = [];
|
// Item may be an array or a regular IteratorAggregate
|
||||||
foreach ($this->item as $record) {
|
if (is_array($this->item)) {
|
||||||
$arrayVersion[] = $record;
|
$this->itemIterator = new ArrayIterator($this->item);
|
||||||
}
|
} else {
|
||||||
|
$this->itemIterator = $this->item->getIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->itemIterator = new ArrayIterator($arrayVersion);
|
// 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;
|
||||||
$this->itemIteratorTotal = count($arrayVersion); // Count the total number of items
|
|
||||||
$this->itemStack[$this->localIndex][SSViewer_Scope::ITEM_ITERATOR_TOTAL] = $this->itemIteratorTotal;
|
$this->itemStack[$this->localIndex][SSViewer_Scope::ITEM_ITERATOR_TOTAL] = $this->itemIteratorTotal;
|
||||||
$this->itemIterator->rewind();
|
|
||||||
} else {
|
} else {
|
||||||
$this->itemIterator->next();
|
$this->itemIterator->next();
|
||||||
}
|
}
|
||||||
|
24
src/View/TemplateIterator.php
Normal file
24
src/View/TemplateIterator.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?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();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user