From 41cbfe4e49970712e4e737776fee313cc2d36fd5 Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Tue, 22 Oct 2024 10:49:17 +1300 Subject: [PATCH] API Combine Sortable, Filterable and Limitable into SS_List --- src/Forms/GridField/GridField.php | 11 +- src/Forms/GridField/GridFieldFilterHeader.php | 7 +- src/Forms/GridField/GridFieldLazyLoader.php | 3 +- src/Forms/GridField/GridFieldPaginator.php | 7 +- .../GridField/GridFieldSortableHeader.php | 7 +- src/Model/List/ArrayList.php | 15 +- src/Model/List/Filterable.php | 107 -------------- src/Model/List/Limitable.php | 32 ----- src/Model/List/ListDecorator.php | 46 +++--- src/Model/List/SS_List.php | 135 ++++++++++++++++++ src/Model/List/Sortable.php | 51 ------- src/ORM/DataList.php | 14 +- src/ORM/EagerLoadedList.php | 8 +- src/ORM/Relation.php | 8 +- src/ORM/Search/BasicSearchContext.php | 14 +- tests/php/Model/List/ArrayListTest.php | 4 +- tests/php/ORM/DataListTest.php | 4 +- tests/php/ORM/EagerLoadedListTest.php | 4 +- 18 files changed, 194 insertions(+), 283 deletions(-) delete mode 100644 src/Model/List/Filterable.php delete mode 100644 src/Model/List/Limitable.php delete mode 100644 src/Model/List/Sortable.php diff --git a/src/Forms/GridField/GridField.php b/src/Forms/GridField/GridField.php index 12b2522c0..a00aab521 100644 --- a/src/Forms/GridField/GridField.php +++ b/src/Forms/GridField/GridField.php @@ -22,9 +22,6 @@ use SilverStripe\Model\List\ArrayList; use SilverStripe\ORM\DataList; use SilverStripe\ORM\DataObjectInterface; use SilverStripe\ORM\FieldType\DBField; -use SilverStripe\Model\List\Filterable; -use SilverStripe\Model\List\Limitable; -use SilverStripe\Model\List\Sortable; use SilverStripe\Model\List\SS_List; use SilverStripe\View\HTML; use SilverStripe\Model\ModelData; @@ -86,7 +83,7 @@ class GridField extends FormField /** * Data source. * - * @var SS_List&Filterable&Sortable&Limitable + * @var SS_List */ protected $list = null; @@ -397,7 +394,7 @@ class GridField extends FormField /** * Set the data source. * - * @param SS_List&Filterable&Sortable&Limitable $list + * @param SS_List $list * * @return $this */ @@ -411,7 +408,7 @@ class GridField extends FormField /** * Get the data source. * - * @return SS_List&Filterable&Sortable&Limitable + * @return SS_List */ public function getList() { @@ -421,7 +418,7 @@ class GridField extends FormField /** * Get the data source after applying every {@link GridField_DataManipulator} to it. * - * @return SS_List&Filterable&Sortable&Limitable + * @return SS_List */ public function getManipulatedList() { diff --git a/src/Forms/GridField/GridFieldFilterHeader.php b/src/Forms/GridField/GridFieldFilterHeader.php index 7a9b0cbd6..eb8b84a4d 100755 --- a/src/Forms/GridField/GridFieldFilterHeader.php +++ b/src/Forms/GridField/GridFieldFilterHeader.php @@ -11,7 +11,6 @@ use SilverStripe\Dev\Deprecation; use SilverStripe\Forms\FieldList; use SilverStripe\Forms\Form; use SilverStripe\Forms\Schema\FormSchema; -use SilverStripe\Model\List\Filterable; use SilverStripe\ORM\Search\SearchContext; use SilverStripe\Model\List\SS_List; use SilverStripe\Model\ArrayData; @@ -109,13 +108,13 @@ class GridFieldFilterHeader extends AbstractGridFieldComponent implements GridFi */ protected function checkDataType($dataList) { - if ($dataList instanceof Filterable) { + if ($dataList instanceof SS_List) { return true; } else { // This will be changed to always throw an exception in a future major release. if ($this->throwExceptionOnBadDataType) { throw new LogicException( - static::class . " expects an SS_Filterable list to be passed to the GridField." + static::class . " expects an SS_List list to be passed to the GridField." ); } return false; @@ -209,7 +208,7 @@ class GridFieldFilterHeader extends AbstractGridFieldComponent implements GridFi public function canFilterAnyColumns($gridField) { $list = $gridField->getList(); - if (!($list instanceof Filterable) || !$this->checkDataType($list)) { + if (!($list instanceof SS_List) || !$this->checkDataType($list)) { return false; } $modelClass = $gridField->getModelClass(); diff --git a/src/Forms/GridField/GridFieldLazyLoader.php b/src/Forms/GridField/GridFieldLazyLoader.php index 59844114e..a6e97405e 100755 --- a/src/Forms/GridField/GridFieldLazyLoader.php +++ b/src/Forms/GridField/GridFieldLazyLoader.php @@ -5,7 +5,6 @@ namespace SilverStripe\Forms\GridField; use SilverStripe\Forms\FormField; use SilverStripe\Forms\TabSet; use SilverStripe\Model\List\ArrayList; -use SilverStripe\Model\List\Filterable; use SilverStripe\Model\List\SS_List; /** @@ -28,7 +27,7 @@ class GridFieldLazyLoader extends AbstractGridFieldComponent implements GridFiel { // If we are lazy loading an empty the list if ($this->isLazy($gridField)) { - if ($dataList instanceof Filterable) { + if ($dataList instanceof SS_List) { // If our original list can be filtered, filter out all results. $dataList = $dataList->byIDs([-1]); } else { diff --git a/src/Forms/GridField/GridFieldPaginator.php b/src/Forms/GridField/GridFieldPaginator.php index fcda7a645..dd5b74970 100755 --- a/src/Forms/GridField/GridFieldPaginator.php +++ b/src/Forms/GridField/GridFieldPaginator.php @@ -3,7 +3,6 @@ namespace SilverStripe\Forms\GridField; use SilverStripe\Core\Config\Configurable; -use SilverStripe\Model\List\Limitable; use SilverStripe\Model\List\SS_List; use SilverStripe\ORM\UnsavedRelationList; use SilverStripe\Model\ArrayData; @@ -89,13 +88,13 @@ class GridFieldPaginator extends AbstractGridFieldComponent implements GridField */ protected function checkDataType($dataList) { - if ($dataList instanceof Limitable) { + if ($dataList instanceof SS_List) { return true; } else { // This will be changed to always throw an exception in a future major release. if ($this->throwExceptionOnBadDataType) { throw new LogicException( - static::class . " expects an SS_Limitable list to be passed to the GridField." + static::class . " expects an SS_List list to be passed to the GridField." ); } return false; @@ -183,7 +182,7 @@ class GridFieldPaginator extends AbstractGridFieldComponent implements GridField $startRow = 0; } - if (!($dataList instanceof Limitable) || ($dataList instanceof UnsavedRelationList)) { + if (!($dataList instanceof SS_List) || ($dataList instanceof UnsavedRelationList)) { return $dataList; } diff --git a/src/Forms/GridField/GridFieldSortableHeader.php b/src/Forms/GridField/GridFieldSortableHeader.php index b3705495c..fe09fb854 100644 --- a/src/Forms/GridField/GridFieldSortableHeader.php +++ b/src/Forms/GridField/GridFieldSortableHeader.php @@ -4,7 +4,6 @@ namespace SilverStripe\Forms\GridField; use SilverStripe\Forms\LiteralField; use SilverStripe\ORM\DataObjectSchema; -use SilverStripe\Model\List\Sortable; use SilverStripe\Model\List\ArrayList; use SilverStripe\Model\List\SS_List; use SilverStripe\ORM\DataObject; @@ -78,13 +77,13 @@ class GridFieldSortableHeader extends AbstractGridFieldComponent implements Grid */ protected function checkDataType($dataList) { - if ($dataList instanceof Sortable) { + if ($dataList instanceof SS_List) { return true; } else { // This will be changed to always throw an exception in a future major release. if ($this->throwExceptionOnBadDataType) { throw new LogicException( - static::class . " expects an SS_Sortable list to be passed to the GridField." + static::class . " expects an SS_List list to be passed to the GridField." ); } return false; @@ -246,7 +245,7 @@ class GridFieldSortableHeader extends AbstractGridFieldComponent implements Grid * {@link DataQuery} first. * * @param GridField $gridField - * @param SS_List&Sortable $dataList + * @param SS_List $dataList * @return SS_List */ public function getManipulatedData(GridField $gridField, SS_List $dataList) diff --git a/src/Model/List/ArrayList.php b/src/Model/List/ArrayList.php index 45f934565..f12346280 100644 --- a/src/Model/List/ArrayList.php +++ b/src/Model/List/ArrayList.php @@ -15,8 +15,8 @@ use Traversable; /** * A list object that wraps around an array of objects or arrays. * - * Note that (like DataLists), the implementations of the methods from SS_Filterable, SS_Sortable and - * SS_Limitable return a new instance of ArrayList, rather than modifying the existing instance. + * Note that (like DataLists), the implementations of the methods from SS_List return a new instance of ArrayList, + * rather than modifying the existing instance. * * For easy reference, methods that operate in this way are: * @@ -28,11 +28,8 @@ use Traversable; * * @template T * @implements SS_List - * @implements Filterable - * @implements Sortable - * @implements Limitable */ -class ArrayList extends ModelData implements SS_List, Filterable, Sortable, Limitable +class ArrayList extends ModelData implements SS_List { use SearchFilterable; @@ -597,7 +594,7 @@ class ArrayList extends ModelData implements SS_List, Filterable, Sortable, Limi /** * Filter the list to include items with these characteristics * - * @see Filterable::filter() + * @see SS_List::filter() * @example $list->filter('Name', 'bob'); // only bob in the list * @example $list->filter('Name', array('aziz', 'bob'); // aziz and bob in list * @example $list->filter(array('Name'=>'bob, 'Age'=>21)); // bob with the Age 21 in list @@ -854,7 +851,7 @@ class ArrayList extends ModelData implements SS_List, Filterable, Sortable, Limi } /** - * @see Filterable::filterByCallback() + * @see SS_List::filterByCallback() * * @example $list = $list->filterByCallback(function($item, $list) { return $item->Age == 9; }) * @param callable $callback @@ -864,7 +861,7 @@ class ArrayList extends ModelData implements SS_List, Filterable, Sortable, Limi { if (!is_callable($callback)) { throw new LogicException(sprintf( - "SS_Filterable::filterByCallback() passed callback must be callable, '%s' given", + "SS_List::filterByCallback() passed callback must be callable, '%s' given", gettype($callback) )); } diff --git a/src/Model/List/Filterable.php b/src/Model/List/Filterable.php deleted file mode 100644 index 3ede8179f..000000000 --- a/src/Model/List/Filterable.php +++ /dev/null @@ -1,107 +0,0 @@ - - */ -interface Filterable extends SS_List -{ - - /** - * Returns TRUE if the list can be filtered by a given field expression. - * - * @param string $by - * @return bool - */ - public function canFilterBy($by); - - /** - * Return a new instance of this list that only includes items with these characteristics - * - * @example $list = $list->filter('Name', 'bob'); // only bob in the list - * @example $list = $list->filter('Name', array('aziz', 'bob'); // aziz and bob in list - * @example $list = $list->filter(array('Name'=>'bob, 'Age'=>21)); // bob with the age 21 - * @example $list = $list->filter(array('Name'=>'bob, 'Age'=>array(21, 43))); // bob with the Age 21 or 43 - * @example $list = $list->filter(array('Name'=>array('aziz','bob'), 'Age'=>array(21, 43))); - * // aziz with the age 21 or 43 and bob with the Age 21 or 43 - * - * @return static - */ - public function filter(); - - /** - * Return a copy of this list which contains items matching any of these characteristics. - * - * @example // only bob in the list - * $list = $list->filterAny('Name', 'bob'); - * // SQL: WHERE "Name" = 'bob' - * @example // azis or bob in the list - * $list = $list->filterAny('Name', array('aziz', 'bob'); - * // SQL: WHERE ("Name" IN ('aziz','bob')) - * @example // bob or anyone aged 21 in the list - * $list = $list->filterAny(array('Name'=>'bob, 'Age'=>21)); - * // SQL: WHERE ("Name" = 'bob' OR "Age" = '21') - * @example // bob or anyone aged 21 or 43 in the list - * $list = $list->filterAny(array('Name'=>'bob, 'Age'=>array(21, 43))); - * // SQL: WHERE ("Name" = 'bob' OR ("Age" IN ('21', '43')) - * @example // all bobs, phils or anyone aged 21 or 43 in the list - * $list = $list->filterAny(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43))); - * // SQL: WHERE (("Name" IN ('bob', 'phil')) OR ("Age" IN ('21', '43')) - * - * @param string|array See {@link filter()} - * @return static - */ - public function filterAny(); - - /** - * Return a new instance of this list that excludes any items with these characteristics - * - * @example $list = $list->exclude('Name', 'bob'); // exclude bob from list - * @example $list = $list->exclude('Name', array('aziz', 'bob'); // exclude aziz and bob from list - * @example $list = $list->exclude(array('Name'=>'bob, 'Age'=>21)); // exclude bob that has Age 21 - * @example $list = $list->exclude(array('Name'=>'bob, 'Age'=>array(21, 43))); // exclude bob with Age 21 or 43 - * @example $list = $list->exclude(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43))); - * // bob age 21 or 43, phil age 21 or 43 would be excluded - * - * @return static - */ - public function exclude(); - - /** - * Return a new instance of this list that excludes any items with these characteristics - * Filter this List by a callback function. The function will be passed each record of the List in turn, - * and must return true for the record to be included. Returns the filtered list. - * - * @example $list = $list->filterByCallback(function($item, $list) { return $item->Age == 9; }) - * @param callable $callback - * @return SS_List - */ - public function filterByCallback($callback); - - /** - * Return the first item with the given ID - * - * @param int $id - * @return T|null - */ - public function byID($id); - - /** - * Filter this list to only contain the given Primary IDs - * - * @param array $ids Array of integers - * @return static - */ - public function byIDs($ids); -} diff --git a/src/Model/List/Limitable.php b/src/Model/List/Limitable.php deleted file mode 100644 index 27a2fe8be..000000000 --- a/src/Model/List/Limitable.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -interface Limitable extends SS_List -{ - - /** - * Returns a new instance of this list 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. - * - * If `$length` is null, then no limit is applied. If `$length` is 0, then an empty list is returned. - * - * @throws InvalidArgumentException if $length or offset are negative - * @return static - */ - public function limit(?int $length, int $offset = 0): Limitable; -} diff --git a/src/Model/List/ListDecorator.php b/src/Model/List/ListDecorator.php index 6cfc963b4..200ab5ba3 100644 --- a/src/Model/List/ListDecorator.php +++ b/src/Model/List/ListDecorator.php @@ -11,33 +11,29 @@ use Traversable; * functionality. It passes through list methods to the underlying list * implementation. * - * @template TList of SS_List&Sortable&Filterable&Limitable * @template T * @implements SS_List - * @implements Sortable - * @implements Filterable - * @implements Limitable */ -abstract class ListDecorator extends ModelData implements SS_List, Sortable, Filterable, Limitable +abstract class ListDecorator extends ModelData implements SS_List { /** - * @var TList + * @var SS_List */ - protected SS_List&Sortable&Filterable&Limitable $list; + protected SS_List $list; /** - * @param TList $list + * @param SS_List $list */ - public function __construct(SS_List&Sortable&Filterable&Limitable $list) + public function __construct(SS_List $list) { $this->setList($list); parent::__construct(); } /** - * @return TList + * @return SS_List */ - public function getList(): SS_List&Sortable&Filterable&Limitable + public function getList(): SS_List { return $this->list; } @@ -48,12 +44,12 @@ abstract class ListDecorator extends ModelData implements SS_List, Sortable, Fil * Useful for keeping a decorator/paginated list configuration intact while modifying * the underlying list. * - * @template TListA + * @template SS_ListA * @template TA - * @param TListA $list - * @return static + * @param SS_ListA $list + * @return static */ - public function setList(SS_List&Sortable&Filterable&Limitable $list): ListDecorator + public function setList(SS_List $list): ListDecorator { $this->list = $list; $this->failover = $this->list; @@ -165,7 +161,7 @@ abstract class ListDecorator extends ModelData implements SS_List, Sortable, Fil } /** - * @return TList + * @return SS_List */ public function each($callback) { @@ -191,7 +187,7 @@ abstract class ListDecorator extends ModelData implements SS_List, Sortable, Fil * @example $list->sort('Name', 'ASC'); * @example $list->sort(array('Name'=>'ASC,'Age'=>'DESC')); * - * @return TList + * @return SS_List */ public function sort() { @@ -211,7 +207,7 @@ abstract class ListDecorator extends ModelData implements SS_List, Sortable, Fil * @example $list->filter(array('Name'=>'bob, 'Age'=>21)); // bob or someone with Age 21 * @example $list->filter(array('Name'=>'bob, 'Age'=>array(21, 43))); // bob or anyone with Age 21 or 43 * - * @return TList + * @return SS_List */ public function filter() { @@ -239,7 +235,7 @@ abstract class ListDecorator extends ModelData implements SS_List, Sortable, Fil * * @param string|array See {@link filter()} * - * @return TList + * @return SS_List */ public function filterAny() { @@ -249,7 +245,7 @@ abstract class ListDecorator extends ModelData implements SS_List, Sortable, Fil /** * Note that, in the current implementation, the filtered list will be an ArrayList, but this may change in a * future implementation. - * @see Filterable::filterByCallback() + * @see SS_List::filterByCallback() * * @example $list = $list->filterByCallback(function($item, $list) { return $item->Age == 9; }) * @param callable $callback @@ -259,7 +255,7 @@ abstract class ListDecorator extends ModelData implements SS_List, Sortable, Fil { if (!is_callable($callback)) { throw new LogicException(sprintf( - "SS_Filterable::filterByCallback() passed callback must be callable, '%s' given", + "SS_List::filterByCallback() passed callback must be callable, '%s' given", gettype($callback) )); } @@ -273,9 +269,9 @@ abstract class ListDecorator extends ModelData implements SS_List, Sortable, Fil } /** - * @return TList + * @return SS_List */ - public function limit(?int $length, int $offset = 0): SS_List&Sortable&Filterable&Limitable + public function limit(?int $length, int $offset = 0): SS_List { return $this->list->limit($length, $offset); } @@ -290,7 +286,7 @@ abstract class ListDecorator extends ModelData implements SS_List, Sortable, Fil * * @param array $ids Array of integers * - * @return TList + * @return SS_List */ public function byIDs($ids) { @@ -305,7 +301,7 @@ abstract class ListDecorator extends ModelData implements SS_List, Sortable, Fil * @example $list->exclude(array('Name'=>'bob, 'Age'=>21)); // exclude bob or someone with Age 21 * @example $list->exclude(array('Name'=>'bob, 'Age'=>array(21, 43))); // exclude bob or anyone with Age 21 or 43 * - * @return TList + * @return SS_List */ public function exclude() { diff --git a/src/Model/List/SS_List.php b/src/Model/List/SS_List.php index 3b788193f..baa109a81 100644 --- a/src/Model/List/SS_List.php +++ b/src/Model/List/SS_List.php @@ -15,6 +15,10 @@ use IteratorAggregate; */ interface SS_List extends ArrayAccess, Countable, IteratorAggregate { + /** + * Representation of the list for use in a template + */ + public function forTemplate(): string; /** * Returns all the items in the list in an array. @@ -94,4 +98,135 @@ interface SS_List extends ArrayAccess, Countable, IteratorAggregate * @return static */ public function each($callback); + + + /** + * Returns TRUE if the list can be filtered by a given field expression. + * + * @param string $by + * @return bool + */ + public function canFilterBy($by); + + /** + * Return a new instance of this list that only includes items with these characteristics + * + * @example $list = $list->filter('Name', 'bob'); // only bob in the list + * @example $list = $list->filter('Name', array('aziz', 'bob'); // aziz and bob in list + * @example $list = $list->filter(array('Name'=>'bob, 'Age'=>21)); // bob with the age 21 + * @example $list = $list->filter(array('Name'=>'bob, 'Age'=>array(21, 43))); // bob with the Age 21 or 43 + * @example $list = $list->filter(array('Name'=>array('aziz','bob'), 'Age'=>array(21, 43))); + * // aziz with the age 21 or 43 and bob with the Age 21 or 43 + * + * @return static + */ + public function filter(); + + /** + * Return a copy of this list which contains items matching any of these characteristics. + * + * @example // only bob in the list + * $list = $list->filterAny('Name', 'bob'); + * // SQL: WHERE "Name" = 'bob' + * @example // azis or bob in the list + * $list = $list->filterAny('Name', array('aziz', 'bob'); + * // SQL: WHERE ("Name" IN ('aziz','bob')) + * @example // bob or anyone aged 21 in the list + * $list = $list->filterAny(array('Name'=>'bob, 'Age'=>21)); + * // SQL: WHERE ("Name" = 'bob' OR "Age" = '21') + * @example // bob or anyone aged 21 or 43 in the list + * $list = $list->filterAny(array('Name'=>'bob, 'Age'=>array(21, 43))); + * // SQL: WHERE ("Name" = 'bob' OR ("Age" IN ('21', '43')) + * @example // all bobs, phils or anyone aged 21 or 43 in the list + * $list = $list->filterAny(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43))); + * // SQL: WHERE (("Name" IN ('bob', 'phil')) OR ("Age" IN ('21', '43')) + * + * @param string|array See {@link filter()} + * @return static + */ + public function filterAny(); + + /** + * Return a new instance of this list that excludes any items with these characteristics + * + * @example $list = $list->exclude('Name', 'bob'); // exclude bob from list + * @example $list = $list->exclude('Name', array('aziz', 'bob'); // exclude aziz and bob from list + * @example $list = $list->exclude(array('Name'=>'bob, 'Age'=>21)); // exclude bob that has Age 21 + * @example $list = $list->exclude(array('Name'=>'bob, 'Age'=>array(21, 43))); // exclude bob with Age 21 or 43 + * @example $list = $list->exclude(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43))); + * // bob age 21 or 43, phil age 21 or 43 would be excluded + * + * @return static + */ + public function exclude(); + + /** + * Return a new instance of this list that excludes any items with these characteristics + * Filter this List by a callback function. The function will be passed each record of the List in turn, + * and must return true for the record to be included. Returns the filtered list. + * + * @example $list = $list->filterByCallback(function($item, $list) { return $item->Age == 9; }) + * @param callable $callback + * @return SS_List + */ + public function filterByCallback($callback); + + /** + * Return the first item with the given ID + * + * @param int $id + * @return T|null + */ + public function byID($id); + + /** + * Filter this list to only contain the given Primary IDs + * + * @param array $ids Array of integers + * @return static + */ + public function byIDs($ids); + + /** + * Returns TRUE if the list can be sorted by a field. + * + * @param string $by + * @return bool + */ + public function canSortBy($by); + + /** + * Return a new instance of this list that is sorted by one or more fields. You can either pass in a single + * field name and direction, or a map of field names to sort directions. + * + * @example $list = $list->sort('Name'); // default ASC sorting + * @example $list = $list->sort('Name DESC'); // DESC sorting + * @example $list = $list->sort('Name', 'ASC'); + * @example $list = $list->sort(array('Name'=>'ASC,'Age'=>'DESC')); + * + * @return static + */ + public function sort(); + + + /** + * Return a new instance of this list based on reversing the current sort. + * + * @example $list = $list->reverse(); + * + * @return static + */ + public function reverse(); + + /** + * Returns a new instance of this list 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. + * + * If `$length` is null, then no limit is applied. If `$length` is 0, then an empty list is returned. + * + * @throws InvalidArgumentException if $length or offset are negative + * @return static + */ + public function limit(?int $length, int $offset = 0): SS_List; } diff --git a/src/Model/List/Sortable.php b/src/Model/List/Sortable.php deleted file mode 100644 index c818cc564..000000000 --- a/src/Model/List/Sortable.php +++ /dev/null @@ -1,51 +0,0 @@ - - */ -interface Sortable extends SS_List -{ - - /** - * Returns TRUE if the list can be sorted by a field. - * - * @param string $by - * @return bool - */ - public function canSortBy($by); - - /** - * Return a new instance of this list that is sorted by one or more fields. You can either pass in a single - * field name and direction, or a map of field names to sort directions. - * - * @example $list = $list->sort('Name'); // default ASC sorting - * @example $list = $list->sort('Name DESC'); // DESC sorting - * @example $list = $list->sort('Name', 'ASC'); - * @example $list = $list->sort(array('Name'=>'ASC,'Age'=>'DESC')); - * - * @return static - */ - public function sort(); - - - /** - * Return a new instance of this list based on reversing the current sort. - * - * @example $list = $list->reverse(); - * - * @return static - */ - public function reverse(); -} diff --git a/src/ORM/DataList.php b/src/ORM/DataList.php index a65f5b161..c582275db 100644 --- a/src/ORM/DataList.php +++ b/src/ORM/DataList.php @@ -14,10 +14,7 @@ use SilverStripe\ORM\Connect\Query; use Traversable; use SilverStripe\ORM\DataQuery; use SilverStripe\Model\List\ArrayList; -use SilverStripe\Model\List\Filterable; -use SilverStripe\Model\List\Limitable; use SilverStripe\Model\List\Map; -use SilverStripe\Model\List\Sortable; use SilverStripe\Model\List\SS_List; use SilverStripe\ORM\Filters\SearchFilterable; @@ -43,11 +40,8 @@ use SilverStripe\ORM\Filters\SearchFilterable; * * @template T of DataObject * @implements SS_List - * @implements Filterable - * @implements Sortable - * @implements Limitable */ -class DataList extends ModelData implements SS_List, Filterable, Sortable, Limitable +class DataList extends ModelData implements SS_List { use SearchFilterable; @@ -474,7 +468,7 @@ class DataList extends ModelData implements SS_List, Filterable, Sortable, Limit * * Raw SQL is not accepted, only actual field names can be passed * - * @see Filterable::filter() + * @see SS_List::filter() * * @example $list = $list->filter('Name', 'bob'); // only bob in the list * @example $list = $list->filter('Name', array('aziz', 'bob'); // aziz and bob in list @@ -591,7 +585,7 @@ class DataList extends ModelData implements SS_List, Filterable, Sortable, Limit /** * Note that, in the current implementation, the filtered list will be an ArrayList, but this may change in a * future implementation. - * @see Filterable::filterByCallback() + * @see SS_List::filterByCallback() * * @example $list = $list->filterByCallback(function($item, $list) { return $item->Age == 9; }) * @param callable $callback @@ -601,7 +595,7 @@ class DataList extends ModelData implements SS_List, Filterable, Sortable, Limit { if (!is_callable($callback)) { throw new LogicException(sprintf( - "SS_Filterable::filterByCallback() passed callback must be callable, '%s' given", + "SS_List::filterByCallback() passed callback must be callable, '%s' given", gettype($callback) )); } diff --git a/src/ORM/EagerLoadedList.php b/src/ORM/EagerLoadedList.php index d65a49d37..c011167de 100644 --- a/src/ORM/EagerLoadedList.php +++ b/src/ORM/EagerLoadedList.php @@ -11,10 +11,7 @@ use InvalidArgumentException; use LogicException; use SilverStripe\Core\ArrayLib; use SilverStripe\Model\List\ArrayList; -use SilverStripe\Model\List\Filterable; -use SilverStripe\Model\List\Limitable; use SilverStripe\Model\List\Map; -use SilverStripe\Model\List\Sortable; use SilverStripe\Model\List\SS_List; use SilverStripe\ORM\Filters\SearchFilterable; use Traversable; @@ -32,11 +29,8 @@ use Traversable; * @template T of DataObject * @implements Relation * @implements SS_List - * @implements Filterable - * @implements Sortable - * @implements Limitable */ -class EagerLoadedList extends ModelData implements Relation, SS_List, Filterable, Sortable, Limitable +class EagerLoadedList extends ModelData implements Relation, SS_List { use SearchFilterable; diff --git a/src/ORM/Relation.php b/src/ORM/Relation.php index 62b2b266c..0bc0d3b02 100644 --- a/src/ORM/Relation.php +++ b/src/ORM/Relation.php @@ -2,9 +2,6 @@ namespace SilverStripe\ORM; -use SilverStripe\Model\List\Filterable; -use SilverStripe\Model\List\Limitable; -use SilverStripe\Model\List\Sortable; use SilverStripe\Model\List\SS_List; use SilverStripe\ORM\FieldType\DBField; @@ -19,11 +16,8 @@ use SilverStripe\ORM\FieldType\DBField; * * @template T * @extends SS_List - * @extends Filterable - * @extends Sortable - * @extends Limitable */ -interface Relation extends SS_List, Filterable, Sortable, Limitable +interface Relation extends SS_List { /** diff --git a/src/ORM/Search/BasicSearchContext.php b/src/ORM/Search/BasicSearchContext.php index c7b106858..5f33be22e 100644 --- a/src/ORM/Search/BasicSearchContext.php +++ b/src/ORM/Search/BasicSearchContext.php @@ -8,11 +8,9 @@ use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Injector\Injector; use SilverStripe\Dev\Deprecation; -use SilverStripe\Model\List\Filterable; use SilverStripe\ORM\Filters\PartialMatchFilter; use SilverStripe\ORM\Filters\SearchFilter; -use SilverStripe\Model\List\Limitable; -use SilverStripe\Model\List\Sortable; +use SilverStripe\Model\List\SS_List; /** * A SearchContext that can be used with non-ORM data. @@ -37,12 +35,12 @@ class BasicSearchContext extends SearchContext * for example "Comments__Name" instead of the filter name "Comments.Name". * @param array|bool|string $sort Field to sort on. * @param array|null|string $limit - * @param Filterable&Sortable&Limitable $existingQuery + * @param SS_List $existingQuery */ - public function getQuery($searchParams, $sort = false, $limit = false, $existingQuery = null): Filterable&Sortable&Limitable + public function getQuery($searchParams, $sort = false, $limit = false, $existingQuery = null): SS_List { - if (!$existingQuery || !($existingQuery instanceof Filterable) || !($existingQuery instanceof Sortable) || !($existingQuery instanceof Limitable)) { - throw new InvalidArgumentException('getQuery requires a pre-existing filterable/sortable/limitable list to be passed as $existingQuery.'); + if (!$existingQuery || !is_a($existingQuery, SS_List::class)) { + throw new InvalidArgumentException('getQuery requires a pre-existing SS_List list to be passed as $existingQuery.'); } if ((count(func_get_args()) >= 3) && (!in_array(gettype($limit), ['array', 'NULL', 'string']))) { @@ -98,7 +96,7 @@ class BasicSearchContext extends SearchContext return $applied; } - private function applyGeneralSearchField(array &$searchParams, Filterable $existingQuery): Filterable + private function applyGeneralSearchField(array &$searchParams, SS_List $existingQuery): SS_List { $generalFieldName = static::config()->get('general_search_field_name'); if (array_key_exists($generalFieldName, $searchParams)) { diff --git a/tests/php/Model/List/ArrayListTest.php b/tests/php/Model/List/ArrayListTest.php index 6aca22cf7..c5ec7ee08 100644 --- a/tests/php/Model/List/ArrayListTest.php +++ b/tests/php/Model/List/ArrayListTest.php @@ -5,7 +5,7 @@ namespace SilverStripe\Model\Tests\List; use SilverStripe\Dev\SapphireTest; use SilverStripe\Model\List\ArrayList; use SilverStripe\ORM\DataObject; -use SilverStripe\Model\List\Filterable; +use SilverStripe\Model\List\SS_List; use SilverStripe\Model\ArrayData; use SilverStripe\Model\List\Map; use stdClass; @@ -1455,7 +1455,7 @@ class ArrayListTest extends SapphireTest $this->assertEquals(2, $list->count()); $this->assertEquals($steve, $list[0]->toMap(), 'List should only contain Steve and Clair'); $this->assertEquals($clair, $list[1]->toMap(), 'List should only contain Steve and Clair'); - $this->assertTrue($list instanceof Filterable, 'The List should be of type SS_Filterable'); + $this->assertTrue($list instanceof SS_List, 'The List should be of type SS_List'); } /** diff --git a/tests/php/ORM/DataListTest.php b/tests/php/ORM/DataListTest.php index bb67daa19..d5618aa01 100755 --- a/tests/php/ORM/DataListTest.php +++ b/tests/php/ORM/DataListTest.php @@ -12,7 +12,7 @@ use SilverStripe\ORM\Connect\MySQLiConnector; use SilverStripe\ORM\DataList; use SilverStripe\ORM\DataQuery; use SilverStripe\ORM\DB; -use SilverStripe\Model\List\Filterable; +use SilverStripe\Model\List\SS_List; use SilverStripe\ORM\Filters\ExactMatchFilter; use SilverStripe\ORM\Tests\DataObjectTest\DataListQueryCounter; use SilverStripe\ORM\Tests\DataObjectTest\Fixture; @@ -1591,7 +1591,7 @@ class DataListTest extends SapphireTest $this->assertEquals(2, $list->count()); $this->assertEquals($expected, $result, 'List should only contain comments from Team 1 (Joe and Bob)'); - $this->assertTrue($list instanceof Filterable, 'The List should be of type SS_Filterable'); + $this->assertTrue($list instanceof SS_List, 'The List should be of type SS_List'); } /** diff --git a/tests/php/ORM/EagerLoadedListTest.php b/tests/php/ORM/EagerLoadedListTest.php index 3eca2f184..ac24e6456 100644 --- a/tests/php/ORM/EagerLoadedListTest.php +++ b/tests/php/ORM/EagerLoadedListTest.php @@ -10,7 +10,7 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\ORM\Connect\MySQLiConnector; use SilverStripe\ORM\EagerLoadedList; use SilverStripe\ORM\DB; -use SilverStripe\Model\List\Filterable; +use SilverStripe\Model\List\SS_List; use SilverStripe\ORM\Tests\DataObjectTest\EquipmentCompany; use SilverStripe\ORM\Tests\DataObjectTest\Fan; use SilverStripe\ORM\Tests\DataObjectTest\Player; @@ -1690,7 +1690,7 @@ class EagerLoadedListTest extends SapphireTest $this->assertEquals(2, $list->count()); $this->assertEquals($expected, $result, 'List should only contain comments from Team 1 (Joe and Bob)'); - $this->assertTrue($list instanceof Filterable, 'The List should be of type SS_Filterable'); + $this->assertTrue($list instanceof SS_List, 'The List should be of type SS_List'); } public function testSimpleExclude()