API CHANGE: Introduce SS_Limitable class for adding to SS_Lists that have limit capability.

API CHANGE: Deprecated SS_List::getRange() in favour of SS_Limitable::limit().
API CHANGE: Introduce SS_Limitable::limit($limit, $offset = 0) as the only modern way of specifying limits; deprecate all others.
This commit is contained in:
Sam Minnee 2012-03-09 14:02:37 +13:00 committed by Stig Lindqvist
parent 193288a021
commit a55e06f6b5
14 changed files with 77 additions and 64 deletions

View File

@ -149,7 +149,7 @@ class PaginatedList extends SS_ListDecorator {
*/ */
public function getIterator() { public function getIterator() {
return new IteratorIterator( return new IteratorIterator(
$this->list->getRange($this->getPageStart(), $this->pageLength) $this->list->limit($this->pageLength, $this->getPageStart())
); );
} }

View File

@ -430,7 +430,7 @@ JS
$SQL_start = 0; $SQL_start = 0;
} }
$items = $items->getRange($SQL_start, $SQL_limit); $items = $items->limit($SQL_limit, $SQL_start);
} }
return $items; return $items;

View File

@ -64,14 +64,14 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
if(!is_int($state->currentPage)) if(!is_int($state->currentPage))
$state->currentPage = 1; $state->currentPage = 1;
if(!$this->getListPaginatable($dataList)) { if(!($dataList instanceof SS_Limitable)) {
return $dataList; return $dataList;
} }
if(!$state->currentPage) { if(!$state->currentPage) {
return $dataList->getRange(0, (int)$this->itemsPerPage); return $dataList->limit((int)$this->itemsPerPage);
} }
$startRow = $this->itemsPerPage * ($state->currentPage - 1); $startRow = $this->itemsPerPage * ($state->currentPage - 1);
return $dataList->getRange((int)$startRow, (int)$this->itemsPerPage); return $dataList->limit((int)$this->itemsPerPage, (int)$startRow);
} }
/** /**
@ -159,14 +159,4 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
return $this->itemsPerPage; return $this->itemsPerPage;
} }
/** Duck check to see if list support methods we need to paginate */
protected function getListPaginatable(SS_List $list) {
// If no list yet, not paginatable
if (!$list) return false;
// Check for methods we use
if(!method_exists($list, 'getRange')) return false;
if(!method_exists($list, 'limit')) return false;
// Default it true
return true;
}
} }

View File

@ -5,7 +5,7 @@
* @package sapphire * @package sapphire
* @subpackage model * @subpackage model
*/ */
class ArrayList extends ViewableData implements SS_List { class ArrayList extends ViewableData implements SS_List, SS_Limitable {
/** /**
* Holds the items in the list * Holds the items in the list
@ -119,6 +119,18 @@ class ArrayList extends ViewableData implements SS_List {
* @return ArrayList * @return ArrayList
*/ */
public function getRange($offset, $length) { public function getRange($offset, $length) {
Deprecation::notice("3.0", 'getRange($offset, $length) is deprecated. Use limit($length, $offset) instead. Note the new argument order.');
return $this->limit($length, $offset);
}
/**
* Get a sub-range of this dataobjectset as an array
*
* @param int $offset
* @param int $length
* @return ArrayList
*/
public function limit($length, $offset = 0) {
return new ArrayList(array_slice($this->items, $offset, $length)); return new ArrayList(array_slice($this->items, $offset, $length));
} }
@ -357,6 +369,15 @@ class ArrayList extends ViewableData implements SS_List {
call_user_func_array('array_multisort', $multisortArgs); call_user_func_array('array_multisort', $multisortArgs);
return $this; return $this;
} }
/**
* Returns true if the given column can be used to filter the records.
*
* It works by checking the fields available in the first record of the list.
*/
public function canFilterBy($by) {
return array_key_exists($by, $this->first());
}
/** /**
* Filter the list to include items with these charactaristics * Filter the list to include items with these charactaristics

View File

@ -6,7 +6,7 @@
* @package sapphire * @package sapphire
* @subpackage model * @subpackage model
*/ */
class DataList extends ViewableData implements SS_List { class DataList extends ViewableData implements SS_List, SS_Limitable {
/** /**
* The DataObject class name that this data list is querying * The DataObject class name that this data list is querying
* *
@ -145,8 +145,11 @@ class DataList extends ViewableData implements SS_List {
* *
* @param string $limit * @param string $limit
*/ */
public function limit($limit) { public function limit($limit, $offset = 0) {
$this->dataQuery->limit($limit); if(!is_numeric($limit)) {
Deprecation::notice('3.0', 'Please pass limits as 2 arguments, rather than an array or SQL fragment.');
}
$this->dataQuery->limit($limit, $offset);
return $this; return $this;
} }
@ -545,7 +548,8 @@ class DataList extends ViewableData implements SS_List {
* @return DataList * @return DataList
*/ */
public function getRange($offset, $length) { public function getRange($offset, $length) {
return $this->limit(array('start' => $offset, 'limit' => $length)); Deprecation::notice("3.0", 'getRange($offset, $length) is deprecated. Use limit($length, $offset) instead. Note the new argument order.');
return $this->limit($length, $offset);
} }
/** /**
@ -813,7 +817,7 @@ class DataList extends ViewableData implements SS_List {
* @return bool * @return bool
*/ */
public function offsetExists($key) { public function offsetExists($key) {
return ($this->getRange($key, 1)->First() != null); return ($this->limit(1,$key)->First() != null);
} }
/** /**
@ -823,7 +827,7 @@ class DataList extends ViewableData implements SS_List {
* @return DataObject * @return DataObject
*/ */
public function offsetGet($key) { public function offsetGet($key) {
return $this->getRange($key, 1)->First(); return $this->limit(1, $key)->First();
} }
/** /**

View File

@ -373,9 +373,9 @@ class DataQuery {
/** /**
* Set the limit of this query * Set the limit of this query
*/ */
function limit($limit) { function limit($limit, $offset = 0) {
$clone = $this; $clone = $this;
$clone->query->limit($limit); $clone->query->limit($limit, $offset);
return $clone; return $clone;
} }

19
model/Limitable.php Normal file
View File

@ -0,0 +1,19 @@
<?php
/**
* Additional interface for {@link SS_List} classes that are limitable - able to have a subset of the list extracted.
*
* @see SS_List, SS_Sortable, SS_Filterable
*/
interface SS_Limitable {
/**
* Returns a filtered version of this where no more than $limit records are included.
* If $offset is specified, then that many records at the beginning of the list will be skipped.
* This matches the behaviour of the SQL LIMIT clause.
*
* @return SS_List
*/
public function limit($limit, $offset = 0);
}

View File

@ -21,15 +21,6 @@ interface SS_List extends ArrayAccess, Countable, IteratorAggregate {
*/ */
public function toNestedArray(); public function toNestedArray();
/**
* Returns a subset of the items within the list.
*
* @param int $offset
* @param int $length
* @return SS_List
*/
public function getRange($offset, $length);
/** /**
* Adds an item to the list, making no guarantees about where it will * Adds an item to the list, making no guarantees about where it will
* appear. * appear.

View File

@ -7,7 +7,7 @@
* @package sapphire * @package sapphire
* @subpackage model * @subpackage model
*/ */
abstract class SS_ListDecorator extends ViewableData implements SS_List { abstract class SS_ListDecorator extends ViewableData implements SS_List, S_Limitable {
protected $list; protected $list;
@ -61,10 +61,6 @@ abstract class SS_ListDecorator extends ViewableData implements SS_List {
$this->list->remove($itemObject); $this->list->remove($itemObject);
} }
public function getRange($offset, $length) {
return $this->list->getRange($offset, $length);
}
public function getIterator() { public function getIterator() {
return $this->list->getIterator(); return $this->list->getIterator();
} }
@ -136,6 +132,10 @@ abstract class SS_ListDecorator extends ViewableData implements SS_List {
return call_user_func_array(array($this->list, 'filter'), $args); return call_user_func_array(array($this->list, 'filter'), $args);
} }
public function limit($length, $offset) {
return $this->list->getRange($length, $offset);
}
/** /**
* Exclude the list to not contain items with these charactaristics * Exclude the list to not contain items with these charactaristics
* *

View File

@ -252,10 +252,10 @@ class SQLQuery {
* @param string|array $limit * @param string|array $limit
* @return SQLQuery This instance * @return SQLQuery This instance
*/ */
public function limit($limit) { public function limit($limit, $offset = 0) {
if($limit && is_numeric($limit)) { if($limit && is_numeric($limit)) {
$this->limit = array( $this->limit = array(
'start' => 0, 'start' => $offset,
'limit' => $limit, 'limit' => $limit,
); );
} else if($limit && is_string($limit)) { } else if($limit && is_string($limit)) {
@ -667,7 +667,7 @@ class SQLQuery {
function firstRow() { function firstRow() {
$query = clone $this; $query = clone $this;
$offset = $this->limit ? $this->limit['start'] : 0; $offset = $this->limit ? $this->limit['start'] : 0;
$query->limit(array('start' => $offset, 'limit' => 1)); $query->limit(1, $offset);
return $query; return $query;
} }
@ -677,7 +677,7 @@ class SQLQuery {
function lastRow() { function lastRow() {
$query = clone $this; $query = clone $this;
$offset = $this->limit ? $this->limit['start'] : 0; $offset = $this->limit ? $this->limit['start'] : 0;
$query->limit(array('start' => $this->count() + $offset - 1, 'limit' => 1)); $query->limit(1, $this->count() + $offset - 1);
return $query; return $query;
} }

View File

@ -61,11 +61,11 @@ class ArrayListTest extends SapphireTest {
)); ));
} }
public function testGetRange() { public function testLimit() {
$list = new ArrayList(array( $list = new ArrayList(array(
array('Key' => 1), array('Key' => 2), array('Key' => 3) array('Key' => 1), array('Key' => 2), array('Key' => 3)
)); ));
$this->assertEquals($list->getRange(1, 2)->toArray(), array( $this->assertEquals($list->limit(2,1)->toArray(), array(
array('Key' => 2), array('Key' => 3) array('Key' => 2), array('Key' => 3)
)); ));
} }

View File

@ -50,7 +50,7 @@ class DataListTest extends SapphireTest {
$this->assertEquals(array('Bob', 'Joe', 'Phil'), $list->column('Name')); $this->assertEquals(array('Bob', 'Joe', 'Phil'), $list->column('Name'));
// We can also restrict the output to a range // We can also restrict the output to a range
$this->assertEquals(array('Joe', 'Phil'), $list->getRange(1,2)->column('Name')); $this->assertEquals(array('Joe', 'Phil'), $list->limit(2, 1)->column('Name'));
} }
function testDataClass() { function testDataClass() {

View File

@ -197,18 +197,12 @@ class DataObjectTest extends SapphireTest {
// There's 4 records in total // There's 4 records in total
$this->assertEquals(4, $players->count()); $this->assertEquals(4, $players->count());
// Testing "## offset ##" syntax
$this->assertEquals(4, $players->limit("20 OFFSET 0")->count());
$this->assertEquals(0, $players->limit("20 OFFSET 20")->count());
$this->assertEquals(2, $players->limit("2 OFFSET 0")->count());
$this->assertEquals(1, $players->limit("5 OFFSET 3")->count());
// Testing "##, ##" syntax // Testing "##, ##" syntax
$this->assertEquals(4, $players->limit("20")->count()); $this->assertEquals(4, $players->limit(20)->count());
$this->assertEquals(4, $players->limit("0, 20")->count()); $this->assertEquals(4, $players->limit(20, 0)->count());
$this->assertEquals(0, $players->limit("20, 20")->count()); $this->assertEquals(0, $players->limit(20, 20)->count());
$this->assertEquals(2, $players->limit("0, 2")->count()); $this->assertEquals(2, $players->limit(2, 0)->count());
$this->assertEquals(1, $players->limit("3, 5")->count()); $this->assertEquals(1, $players->limit(5, 3)->count());
} }
/** /**

View File

@ -87,19 +87,13 @@ class SQLQueryTest extends SapphireTest {
// numeric limit // numeric limit
$query = new SQLQuery(); $query = new SQLQuery();
$query->from[] = "MyTable"; $query->from[] = "MyTable";
$query->limit("99"); $query->limit(99);
$this->assertEquals("SELECT * FROM MyTable LIMIT 99", $query->sql()); $this->assertEquals("SELECT * FROM MyTable LIMIT 99", $query->sql());
// array limit
$query = new SQLQuery();
$query->from[] = "MyTable";
$query->limit(array('limit'=>99));
$this->assertEquals("SELECT * FROM MyTable LIMIT 99", $query->sql());
// array limit with start (MySQL specific) // array limit with start (MySQL specific)
$query = new SQLQuery(); $query = new SQLQuery();
$query->from[] = "MyTable"; $query->from[] = "MyTable";
$query->limit(array('limit'=>99, 'start'=>97)); $query->limit(99, 97);
$this->assertEquals("SELECT * FROM MyTable LIMIT 99 OFFSET 97", $query->sql()); $this->assertEquals("SELECT * FROM MyTable LIMIT 99 OFFSET 97", $query->sql());
} }
} }