Merge pull request #10 from silverstripeltd/pulls/5/list-generics

MNT Add generics to list
This commit is contained in:
Guy Sartorelli 2023-11-15 13:59:12 +13:00 committed by GitHub
commit 8e399a42a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 237 additions and 142 deletions

View File

@ -35,6 +35,12 @@ use SilverStripe\ORM\Filters\SearchFilterable;
* - removeAll
*
* Subclasses of DataList may add other methods that have the same effect.
*
* @template T of DataObject
* @implements SS_List<T>
* @implements Filterable<T>
* @implements Sortable<T>
* @implements Limitable<T>
*/
class DataList extends ViewableData implements SS_List, Filterable, Sortable, Limitable
{
@ -49,7 +55,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
/**
* The DataObject class name that this data list is querying
*
* @var string
* @var class-string<T>
*/
protected $dataClass;
@ -63,7 +69,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
/**
* A cached Query to save repeated database calls. {@see DataList::getTemplateIteratorCount()}
*
* @var SilverStripe\ORM\Connect\Query
* @var Query
*/
protected $finalisedQuery;
@ -89,7 +95,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Create a new DataList.
* No querying is done on construction, but the initial query schema is set up.
*
* @param string $dataClass - The DataObject class to query.
* @param class-string<T> $dataClass - The DataObject class to query.
*/
public function __construct($dataClass)
{
@ -102,7 +108,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
/**
* Get the dataClass name for this DataList, ie the DataObject ClassName
*
* @return string
* @return class-string<T>
*/
public function dataClass()
{
@ -150,7 +156,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* alterDataQuery
*
* @param callable $callback
* @return static
* @return static<T>
* @throws Exception
*/
public function alterDataQuery($callback)
@ -187,7 +193,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Return a new DataList instance with the underlying {@link DataQuery} object changed
*
* @param DataQuery $dataQuery
* @return static
* @return static<T>
*/
public function setDataQuery(DataQuery $dataQuery)
{
@ -201,7 +207,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*
* @param string|array $keyOrArray Either the single key to set, or an array of key value pairs to set
* @param mixed $val If $keyOrArray is not an array, this is the value to set
* @return static
* @return static<T>
*/
public function setDataQueryParam($keyOrArray, $val = null)
{
@ -242,7 +248,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*
* @param string|array|SQLConditionGroup $filter Predicate(s) to set, as escaped SQL statements or
* paramaterised queries
* @return static
* @return static<T>
*/
public function where($filter)
{
@ -264,7 +270,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*
* @param string|array|SQLConditionGroup $filter Predicate(s) to set, as escaped SQL statements or
* paramaterised queries
* @return static
* @return static<T>
*/
public function whereAny($filter)
{
@ -336,7 +342,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Return a new DataList instance with distinct records or not
*
* @param bool $value
* @return static
* @return static<T>
*/
public function distinct($value)
{
@ -446,6 +452,8 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*
* This method accepts raw SQL so could be vulnerable to SQL injection attacks if used incorrectly,
* it's preferable to use sort() instead which does not allow raw SQL
*
* @return static<T>
*/
public function orderBy(string $orderBy): static
{
@ -473,7 +481,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* ->filter('Field:not', null) will generate '"Field" IS NOT NULL'
*
* @param string|array Escaped SQL statement. If passed as array, all keys and values will be escaped internally
* @return $this
* @return static<T>
*/
public function filter()
{
@ -499,7 +507,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Return a new instance of the list with an added filter
*
* @param array $filterArray
* @return $this
* @return static<T>
*/
public function addFilter($filterArray)
{
@ -535,7 +543,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* // SQL: WHERE (("Name" IN ('bob', 'phil')) OR ("Age" IN ('21', '43'))
*
* @param string|array See {@link filter()}
* @return static
* @return static<T>
*/
public function filterAny()
{
@ -580,7 +588,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*
* @example $list = $list->filterByCallback(function($item, $list) { return $item->Age == 9; })
* @param callable $callback
* @return ArrayList (this may change in future implementations)
* @return ArrayList<T> (this may change in future implementations)
*/
public function filterByCallback($callback)
{
@ -620,7 +628,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* @param string $columnName Quoted column name (by reference)
* @param bool $linearOnly Set to true to restrict to linear relations only. Set this
* if this relation will be used for sorting, and should not include duplicate rows.
* @return $this DataList with this relation applied
* @return static<T> DataList with this relation applied
*/
public function applyRelation($field, &$columnName = null, $linearOnly = false)
{
@ -678,7 +686,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* @param string|array
* @param string [optional]
*
* @return $this
* @return static<T>
*/
public function exclude()
{
@ -718,7 +726,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* @param string|array
* @param string [optional]
*
* @return $this
* @return static<T>
*/
public function excludeAny()
{
@ -747,8 +755,8 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*
* The $list passed needs to contain the same dataclass as $this
*
* @param DataList $list
* @return static
* @param DataList<T> $list
* @return static<T>
* @throws InvalidArgumentException
*/
public function subtract(DataList $list)
@ -772,7 +780,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* will cause the query to appear first. The default is 20, and joins created automatically by the
* ORM have a value of 10.
* @param array $parameters Any additional parameters if the join is a parameterised subquery
* @return static
* @return static<T>
*/
public function innerJoin($table, $onClause, $alias = null, $order = 20, $parameters = [])
{
@ -791,7 +799,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* will cause the query to appear first. The default is 20, and joins created automatically by the
* ORM have a value of 10.
* @param array $parameters Any additional parameters if the join is a parameterised subquery
* @return static
* @return static<T>
*/
public function leftJoin($table, $onClause, $alias = null, $order = 20, $parameters = [])
{
@ -810,7 +818,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* will cause the query to appear first. The default is 20, and joins created automatically by the
* ORM have a value of 10.
* @param array $parameters Any additional parameters if the join is a parameterised subquery
* @return static
* @return static<T>
*/
public function rightJoin($table, $onClause, $alias = null, $order = 20, $parameters = [])
{
@ -823,7 +831,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Return an array of the actual items that this DataList contains at this stage.
* This is when the query is actually executed.
*
* @return array
* @return array<T>
*/
public function toArray()
{
@ -856,7 +864,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Walks the list using the specified callback
*
* @param callable $callback
* @return $this
* @return static<T> $this
*/
public function each($callback)
{
@ -894,7 +902,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* If called without $row['ID'] set, then a new object will be created rather than rehydrated.
*
* @param array $row
* @return DataObject
* @return T
*/
public function createDataObject($row)
{
@ -946,6 +954,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
/**
* Returns an Iterator for this DataList.
* This function allows you to use DataLists in foreach loops
* @return iterable<T>
*/
public function getIterator(): Traversable
{
@ -1457,6 +1466,8 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*
* IMPORTANT: Calling eagerLoad() will cause any relations on DataObjects to be returned as an EagerLoadedList
* instead of a subclass of DataList such as HasManyList i.e. MyDataObject->MyHasManyRelation() returns an EagerLoadedList
*
* @return static<T>
*/
public function eagerLoad(...$relationChains): static
{
@ -1552,7 +1563,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*
* The object returned is not cached, unlike {@link DataObject::get_one()}
*
* @return DataObject|null
* @return T|null
*/
public function first()
{
@ -1572,7 +1583,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*
* The object returned is not cached, unlike {@link DataObject::get_one()}
*
* @return DataObject|null
* @return T|null
*/
public function last()
{
@ -1605,7 +1616,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*
* @param string $key
* @param string $value
* @return DataObject|null
* @return T|null
*/
public function find($key, $value)
{
@ -1616,7 +1627,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Restrict the columns to fetch into this DataList
*
* @param array $queriedColumns
* @return static
* @return static<T>
*/
public function setQueriedColumns($queriedColumns)
{
@ -1629,7 +1640,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Filter this list to only contain the given Primary IDs
*
* @param array $ids Array of integers
* @return $this
* @return static<T>
*/
public function byIDs($ids)
{
@ -1642,7 +1653,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* The object returned is not cached, unlike {@link DataObject::get_by_id()}
*
* @param int $id
* @return DataObject|null
* @return T|null
*/
public function byID($id)
{
@ -1734,13 +1745,13 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* DataList::Create(\SilverStripe\Security\Group::class)->relation("Members")
*
* @param string $relationName
* @return HasManyList|ManyManyList
* @return RelationList<T>
*/
public function relation($relationName)
{
$ids = $this->column('ID');
$singleton = DataObject::singleton($this->dataClass);
/** @var HasManyList|ManyManyList $relation */
/** @var RelationList $relation */
$relation = $singleton->$relationName($ids);
return $relation;
}
@ -1753,8 +1764,8 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
/**
* Add a number of items to the component set.
*
* @param array $items Items to add, as either DataObjects or IDs.
* @return $this
* @param array<T> $items Items to add, as either DataObjects or IDs.
* @return static<T> $this
*/
public function addMany($items)
{
@ -1768,7 +1779,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Remove the items from this list with the given IDs
*
* @param array $idList
* @return $this
* @return static<T> $this
*/
public function removeMany($idList)
{
@ -1782,7 +1793,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Remove every element in this DataList matching the given $filter.
*
* @param string|array $filter - a sql type where filter
* @return $this
* @return static<T> $this
*/
public function removeByFilter($filter)
{
@ -1795,7 +1806,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
/**
* Shuffle the datalist using a random function provided by the SQL engine
*
* @return $this
* @return static<T>
*/
public function shuffle()
{
@ -1805,7 +1816,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
/**
* Remove every element in this DataList.
*
* @return $this
* @return static<T> $this
*/
public function removeAll()
{
@ -1819,7 +1830,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* This method are overloaded by HasManyList and ManyMany list to perform more sophisticated
* list manipulation
*
* @param mixed $item
* @param T $item
*/
public function add($item)
{
@ -1831,7 +1842,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Return a new item to add to this DataList.
*
* @param array $initialFields
* @return DataObject
* @return T
*/
public function newObject($initialFields = null)
{
@ -1842,7 +1853,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
/**
* Remove this item by deleting it
*
* @param DataObject $item
* @param T $item
*/
public function remove($item)
{
@ -1867,7 +1878,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
/**
* Reverses a list of items.
*
* @return static
* @return static<T>
*/
public function reverse()
{
@ -1888,6 +1899,8 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* Returns item stored in list with index $key
*
* The object returned is not cached, unlike {@link DataObject::get_one()}
*
* @return T|null
*/
public function offsetGet(mixed $key): ?DataObject
{
@ -1896,6 +1909,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
/**
* Set an item with the key in $key
*
* @throws BadMethodCallException
*/
public function offsetSet(mixed $key, mixed $value): void
@ -1922,7 +1936,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*
* @param int $chunkSize
* @throws InvalidArgumentException If `$chunkSize` has an invalid size.
* @return Generator|DataObject[]
* @return iterable<T>
*/
public function chunkedFetch(int $chunkSize = 1000): iterable
{

View File

@ -716,7 +716,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* or destroy and reinstanciate the record.
*
* @param string $className The new ClassName attribute (a subclass of {@link DataObject})
* @return $this
* @return static $this
*/
public function setClassName($className)
{
@ -742,9 +742,10 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* there is no record, or the record has no ID. In this case, we do have an ID but
* we still need to repopulate the defaults.
*
* @param string $newClassName The name of the new class
* @template T of DataObject
* @param class-string<T> $newClassName The name of the new class
*
* @return DataObject The new instance of the new class, The exact type will be of the class name provided.
* @return T The new instance of the new class, The exact type will be of the class name provided.
*/
public function newClassInstance($newClassName)
{
@ -963,7 +964,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* Returns the associated database record - in this case, the object itself.
* This is included so that you can call $dataOrController->data() and get a DataObject all the time.
*
* @return DataObject Associated database record
* @return static Associated database record
*/
public function data()
{
@ -1012,7 +1013,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* whitelist the allowed keys.
*
* @param array $data A map of field name to data values to update.
* @return DataObject $this
* @return static $this
*/
public function update($data)
{
@ -1073,7 +1074,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* use the write() method.
*
* @param array $data A map of field name to data values to update.
* @return DataObject $this
* @return static $this
*/
public function castedUpdate($data)
{
@ -1097,7 +1098,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* Caution: Does not delete the merged object.
* Caution: Does now overwrite Created date on the original object.
*
* @param DataObject $rightObj
* @param static $rightObj
* @param string $priority left|right Determines who wins in case of a conflict (optional)
* @param bool $includeRelations Merge any existing relations (optional)
* @param bool $overwriteWithEmpty Overwrite existing left values with empty right values.
@ -1182,7 +1183,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* next write. Existing CHANGE_VALUE or CHANGE_STRICT values
* are preserved.
*
* @return $this
* @return static $this
*/
public function forceChange()
{
@ -1303,7 +1304,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* Called by the constructor when creating new records.
*
* @uses DataExtension::populateDefaults()
* @return DataObject $this
* @return static $this
*/
public function populateDefaults()
{
@ -1654,7 +1655,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*
* @param bool $recursive Recursively write components
* @param array $skip List of DataObject references to skip
* @return DataObject $this
* @return static $this
*/
public function writeComponents($recursive = false, $skip = [])
{
@ -1888,7 +1889,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*
* @param string $componentName
* @param DataObject|null $item
* @return $this
* @return static $this
*/
public function setComponent($componentName, $item)
{
@ -2327,7 +2328,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* Generates a SearchContext to be used for building and processing
* a generic search form for properties on this object.
*
* @return SearchContext
* @return SearchContext<static>
*/
public function getDefaultSearchContext()
{
@ -2817,7 +2818,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*
* @param string $fieldName Name of the field
* @param mixed $val New field value
* @return $this
* @return static $this
*/
public function setField($fieldName, $val)
{
@ -2913,7 +2914,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*
* @param string $fieldName Name of the field
* @param mixed $value New field value
* @return $this
* @return static $this
*/
public function setCastedField($fieldName, $value)
{
@ -2992,7 +2993,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* See {@link extendedCan()} for a more versatile tri-state permission control.
*
* @param string $perm The permission to be checked, such as 'View'.
* @param Member $member The member whose permissions need checking. Defaults to the currently logged
* @param Member|null $member The member whose permissions need checking. Defaults to the currently logged
* in user.
* @param array $context Additional $context to pass to extendedCan()
*
@ -3038,7 +3039,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* </code>
*
* @param string $methodName Method on the same object, e.g. {@link canEdit()}
* @param Member|int $member
* @param Member|null $member
* @param array $context Optional context
* @return boolean|null
*/
@ -3060,7 +3061,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
}
/**
* @param Member $member
* @param Member|null $member
* @return boolean
*/
public function canView($member = null)
@ -3073,7 +3074,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
}
/**
* @param Member $member
* @param Member|null $member
* @return boolean
*/
public function canEdit($member = null)
@ -3086,7 +3087,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
}
/**
* @param Member $member
* @param Member|null $member
* @return boolean
*/
public function canDelete($member = null)
@ -3099,7 +3100,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
}
/**
* @param Member $member
* @param Member|null $member
* @param array $context Additional context-specific data which might
* affect whether (or where) this object could be created.
* @return boolean
@ -3285,7 +3286,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* Return all objects matching the filter
* sub-classes are automatically selected and included
*
* @param string $callerClass The class of objects to be returned
* @param string|null $callerClass The class of objects to be returned
* @param string|array $filter A filter to be inserted into the WHERE clause.
* Supports parameterised queries. See SQLSelect::addWhere() for syntax examples.
* @param string|array|null $sort Passed to DataList::sort()
@ -3294,7 +3295,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* @param string|array $limit A limit expression to be inserted into the LIMIT clause.
* @param string $containerClass The container class to return the results in.
*
* @return DataList The objects matching the filter, in the class specified by $containerClass
* @return DataList<static> The objects matching the filter, in the class specified by $containerClass
*/
public static function get(
$callerClass = null,
@ -3360,7 +3361,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* @param boolean $cache Use caching
* @param string|array|null $sort Passed to DataList::sort() so that DataList::first() returns the desired item
*
* @return DataObject|null The first item matching the query
* @return static|null The first item matching the query
*/
public static function get_one($callerClass = null, $filter = "", $cache = true, $sort = "")
{
@ -3411,7 +3412,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*
* @param boolean $persistent When true will also clear persistent data stored in the Cache system.
* When false will just clear session-local cached data
* @return DataObject $this
* @return static $this
*/
public function flushCache($persistent = true)
{
@ -3512,7 +3513,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
/**
* Get the base class for this object
*
* @return string
* @return class-string<DataObject>
*/
public function baseClass()
{
@ -3569,7 +3570,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
/**
* @see $sourceQueryParams
* @param string $key
* @return string
* @return string|null
*/
public function getSourceQueryParam($key)
{
@ -4314,7 +4315,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*
* @param DataObject $object
* @param string $alias Alias
* @return $this
* @return static $this
*/
public function setJoin(DataObject $object, $alias = null)
{

View File

@ -21,6 +21,13 @@ use Traversable;
*
* Note that when this list represents a relation, adding items to or removing items from this list will NOT
* affect the underlying relation in the database. This list is read-only.
*
* @template T of DataObject
* @implements Relation<T>
* @implements SS_List<T>
* @implements Filterable<T>
* @implements Sortable<T>
* @implements Limitable<T>
*/
class EagerLoadedList extends ViewableData implements Relation, SS_List, Filterable, Sortable, Limitable
{
@ -28,11 +35,13 @@ class EagerLoadedList extends ViewableData implements Relation, SS_List, Filtera
/**
* List responsible for instantiating the actual DataObject objects from eager-loaded data
* @var DataList<T>
*/
private DataList $dataList;
/**
* Underlying DataObject class for this list
* @var class-string<T>
*/
private string $dataClass;
@ -65,6 +74,9 @@ class EagerLoadedList extends ViewableData implements Relation, SS_List, Filtera
*/
private array $manyManyComponent = [];
/**
* @param class-string<T> $dataClass
*/
public function __construct(string $dataClass, string $dataListClass, int|array|null $foreignID = null, array $manyManyComponent = [])
{
if (!is_a($dataListClass, DataList::class, true)) {
@ -134,7 +146,7 @@ class EagerLoadedList extends ViewableData implements Relation, SS_List, Filtera
/**
* Pass in any eager-loaded data which applies to relations on a specific record in this list
*
* @return $this
* @return static<T> $this
*/
public function addEagerLoadedData(string $relation, int $id, self|DataObject $data): static
{
@ -144,6 +156,8 @@ class EagerLoadedList extends ViewableData implements Relation, SS_List, Filtera
/**
* Get the dataClass name for this list, ie the DataObject ClassName
*
* @return class-string<T>
*/
public function dataClass(): string
{
@ -179,6 +193,9 @@ class EagerLoadedList extends ViewableData implements Relation, SS_List, Filtera
throw new BadMethodCallException("Can't change the foreign ID for an EagerLoadedList");
}
/**
* @return iterator<T>
*/
public function getIterator(): Traversable
{
$limitedRows = $this->getFinalisedRows();
@ -493,6 +510,8 @@ class EagerLoadedList extends ViewableData implements Relation, SS_List, Filtera
/**
* Return a copy of this list which does not contain any items with any of these params
*
* @return static<T>
*/
public function excludeAny(...$args): static
{
@ -509,6 +528,7 @@ class EagerLoadedList extends ViewableData implements Relation, SS_List, Filtera
* Return a new instance of the list with an added filter
*
* @param array $filterArray
* @return static<T>
*/
public function addFilter($filterArray): static
{
@ -522,6 +542,7 @@ class EagerLoadedList extends ViewableData implements Relation, SS_List, Filtera
*
* The $list passed needs to contain the same dataclass as $this
*
* @return static<T>
* @throws InvalidArgumentException
*/
public function subtract(DataList $list): static
@ -708,6 +729,8 @@ class EagerLoadedList extends ViewableData implements Relation, SS_List, Filtera
/**
* Shuffle the items in this list
*
* @return static<T>
*/
public function shuffle(): static
{
@ -862,6 +885,8 @@ class EagerLoadedList extends ViewableData implements Relation, SS_List, Filtera
* At a minimum, $row['ID'] must be set. Unsaved records cannot be eager loaded.
*
* @param array $row
* @return T
* @throws InvalidArgumentException if $row has no "ID" key
*/
public function createDataObject($row): DataObject
{

View File

@ -11,6 +11,9 @@ namespace SilverStripe\ORM;
* @see SS_List
* @see Sortable
* @see Limitable
*
* @template T
* @implements SS_List<T>
*/
interface Filterable extends SS_List
{
@ -33,6 +36,8 @@ interface Filterable extends SS_List
* @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<T>
*/
public function filter();
@ -56,7 +61,7 @@ interface Filterable extends SS_List
* // SQL: WHERE (("Name" IN ('bob', 'phil')) OR ("Age" IN ('21', '43'))
*
* @param string|array See {@link filter()}
* @return static
* @return static<T>
*/
public function filterAny();
@ -70,6 +75,8 @@ interface Filterable extends SS_List
* @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<T>
*/
public function exclude();
@ -80,7 +87,7 @@ interface Filterable extends SS_List
*
* @example $list = $list->filterByCallback(function($item, $list) { return $item->Age == 9; })
* @param callable $callback
* @return Filterable
* @return Filterable<T>
*/
public function filterByCallback($callback);
@ -88,7 +95,7 @@ interface Filterable extends SS_List
* Return the first item with the given ID
*
* @param int $id
* @return mixed
* @return T|null
*/
public function byID($id);
@ -96,7 +103,7 @@ interface Filterable extends SS_List
* Filter this list to only contain the given Primary IDs
*
* @param array $ids Array of integers
* @return SS_List
* @return static<T>
*/
public function byIDs($ids);
}

View File

@ -6,10 +6,12 @@ use InvalidArgumentException;
/**
* Subclass of {@link DataList} representing a has_many relation.
*
* @template T of DataObject
* @extends RelationList<T>
*/
class HasManyList extends RelationList
{
/**
* @var string
*/
@ -21,7 +23,7 @@ class HasManyList extends RelationList
* {@link DataList} methods. Addition arguments are used to support {@link add()}
* and {@link remove()} methods.
*
* @param string $dataClass The class of the DataObjects that this will list.
* @param class-string<T> $dataClass The class of the DataObjects that this will list.
* @param string $foreignKey The name of the foreign key field to set the ID filter against.
*/
public function __construct($dataClass, $foreignKey)
@ -43,7 +45,7 @@ class HasManyList extends RelationList
/**
* @param null|int|array|string $id
* @return array
* @return array|null
*/
protected function foreignIDFilter($id = null)
{
@ -68,7 +70,7 @@ class HasManyList extends RelationList
*
* It does so by setting the relationFilters.
*
* @param DataObject|int $item The DataObject to be added, or its ID
* @param T|int $item The DataObject to be added, or its ID
*/
public function add($item)
{
@ -118,7 +120,7 @@ class HasManyList extends RelationList
* Remove an item from this relation.
* Doesn't actually remove the item, it just clears the foreign key value.
*
* @param DataObject $item The DataObject to be removed
* @param T $item The DataObject to be removed
*/
public function remove($item)
{

View File

@ -11,6 +11,9 @@ namespace SilverStripe\ORM;
* @see SS_List
* @see Sortable
* @see Filterable
*
* @template T
* @implements SS_List<T>
*/
interface Limitable extends SS_List
{
@ -22,6 +25,7 @@ interface Limitable extends SS_List
*
* If `$length` is null, then no limit is applied. If `$length` is 0, then an empty list is returned.
*
* @return static<T>
* @throws InvalidArgumentException if $length or offset are negative
*/
public function limit(?int $length, int $offset = 0): Limitable;

View File

@ -12,6 +12,9 @@ use Exception;
/**
* Subclass of {@link DataList} representing a many_many relation.
*
* @template T of DataObject
* @extends RelationList<T>
*/
class ManyManyList extends RelationList
{
@ -50,7 +53,7 @@ class ManyManyList extends RelationList
* the normal {@link DataList} methods. Addition arguments are used to
* support {@link add()} and {@link remove()} methods.
*
* @param string $dataClass The class of the DataObjects that this will list.
* @param class-string<T> $dataClass The class of the DataObjects that this will list.
* @param string $joinTable The name of the table whose entries define the content of this many_many relation.
* @param string $localKey The key in the join table that maps to the dataClass' PK.
* @param string $foreignKey The key in the join table that maps to joined class' PK.
@ -124,7 +127,7 @@ class ManyManyList extends RelationList
* Create a DataObject from the given SQL row.
*
* @param array $row
* @return DataObject
* @return T
*/
public function createDataObject($row)
{
@ -166,7 +169,7 @@ class ManyManyList extends RelationList
*
* @param int|null|string|array $id
*
* @return array
* @return array|null
*/
protected function foreignIDFilter($id = null)
{
@ -214,10 +217,11 @@ class ManyManyList extends RelationList
* @throws InvalidArgumentException
* @throws Exception
*
* @param DataObject|int $item
* @param T|int $item
* @param array $extraFields A map of additional columns to insert into the joinTable.
* Column names should be ANSI quoted.
* @throws Exception
* @throws BadMethodCallException
* @throws InvalidArgumentException
*/
public function add($item, $extraFields = [])
{
@ -335,7 +339,7 @@ class ManyManyList extends RelationList
* Note that for a ManyManyList, the item is never actually deleted, only
* the join table is affected.
*
* @param DataObject $item
* @param T $item
*/
public function remove($item)
{

View File

@ -9,6 +9,9 @@ use SilverStripe\Core\Injector\Injector;
/**
* ManyManyList backed by a dataobject join table
*
* @template T of DataObject
* @extends RelationList<T>
*/
class ManyManyThroughList extends RelationList
{
@ -21,7 +24,7 @@ class ManyManyThroughList extends RelationList
* Create a new ManyManyRelationList object. This relation will utilise an intermediary dataobject
* as a join table, unlike ManyManyList which scaffolds a table automatically.
*
* @param string $dataClass The class of the DataObjects that this will list.
* @param class-string<T> $dataClass The class of the DataObjects that this will list.
* @param string $joinClass Class name of the joined dataobject record
* @param string $localKey The key in the join table that maps to the dataClass' PK.
* @param string $foreignKey The key in the join table that maps to joined class' PK.
@ -101,7 +104,7 @@ class ManyManyThroughList extends RelationList
* Note that for a ManyManyList, the item is never actually deleted, only
* the join table is affected.
*
* @param DataObject $item
* @param T $item
*/
public function remove($item)
{
@ -169,7 +172,7 @@ class ManyManyThroughList extends RelationList
}
/**
* @param mixed $item
* @param T $item
* @param array $extraFields
*/
public function add($item, $extraFields = [])
@ -216,7 +219,7 @@ class ManyManyThroughList extends RelationList
$foreignKey = $this->manipulator->getForeignIDKey();
$hasManyList = $this->manipulator->getParentRelationship($this->dataQuery());
$records = $hasManyList->filter($localKey, $itemID);
/** @var DataObject $record */
foreach ($records as $record) {
if ($extraFields) {
foreach ($extraFields as $field => $value) {

View File

@ -9,6 +9,10 @@ use SilverStripe\ORM\Queries\SQLSelect;
/**
* Injected into DataQuery to augment getFinalisedQuery() with a join table
*
* @template TJoin of DataObject
* @template TParent of DataObject
* @template TForeign of DataObject
*/
class ManyManyThroughQueryManipulator implements DataQueryManipulator
{
@ -18,7 +22,7 @@ class ManyManyThroughQueryManipulator implements DataQueryManipulator
/**
* DataObject that backs the joining table
*
* @var string
* @var class-string<TJoin>
*/
protected $joinClass;
@ -39,20 +43,24 @@ class ManyManyThroughQueryManipulator implements DataQueryManipulator
/**
* Foreign class 'from' property. Normally not needed unless polymorphic.
*
* @var string
* @var class-string<TForeign>
*/
protected $foreignClass;
/**
* Class name of instance that owns this list
*
* @var string
* @var class-string<TParent>
*/
protected $parentClass;
/**
* Build query manipulator for a given join table. Additional parameters (foreign key, etc)
* will be inferred at evaluation from query parameters set via the ManyManyThroughList
*
* @param class-string<TJoin> $joinClass
* @param class-string<TForeign> $foreignClass
* @param class-string<TParent> $parentClass
*/
public function __construct(string $joinClass, string $localKey, string $foreignKey, string $foreignClass, string $parentClass)
{
@ -68,7 +76,7 @@ class ManyManyThroughQueryManipulator implements DataQueryManipulator
}
/**
* @return string
* @return class-string<TJoin>
*/
public function getJoinClass()
{
@ -76,7 +84,7 @@ class ManyManyThroughQueryManipulator implements DataQueryManipulator
}
/**
* @param mixed $joinClass
* @param class-string<TJoin> $joinClass
* @return $this
*/
public function setJoinClass($joinClass)
@ -152,7 +160,7 @@ class ManyManyThroughQueryManipulator implements DataQueryManipulator
* Get has_many relationship between parent and join table (for a given DataQuery)
*
* @param DataQuery $query
* @return HasManyList
* @return HasManyList<TJoin>
*/
public function getParentRelationship(DataQuery $query)
{
@ -280,7 +288,7 @@ class ManyManyThroughQueryManipulator implements DataQueryManipulator
}
/**
* @return string
* @return class-string<TForeign>
*/
public function getForeignClass()
{
@ -288,7 +296,7 @@ class ManyManyThroughQueryManipulator implements DataQueryManipulator
}
/**
* @param string $foreignClass
* @param class-string<TForeign> $foreignClass
* @return $this
*/
public function setForeignClass($foreignClass)
@ -298,7 +306,7 @@ class ManyManyThroughQueryManipulator implements DataQueryManipulator
}
/**
* @return string
* @return class-string<TParent>
*/
public function getParentClass()
{
@ -306,8 +314,8 @@ class ManyManyThroughQueryManipulator implements DataQueryManipulator
}
/**
* @param string $parentClass
* @return ManyManyThroughQueryManipulator
* @param class-string<TParent> $parentClass
* @return $this
*/
public function setParentClass($parentClass)
{

View File

@ -8,6 +8,10 @@ use InvalidArgumentException;
/**
* Represents a has_many list linked against a polymorphic relationship
*
* @template T of DataObject
* @template TForeign of DataObject
* @extends HasManyList<T>
*/
class PolymorphicHasManyList extends HasManyList
{
@ -22,7 +26,7 @@ class PolymorphicHasManyList extends HasManyList
/**
* Retrieve the name of the class this relation is filtered by
*
* @return string
* @return class-string<TForeign>
*/
public function getForeignClass()
{
@ -40,10 +44,10 @@ class PolymorphicHasManyList extends HasManyList
/**
* Create a new PolymorphicHasManyList relation list.
*
* @param string $dataClass The class of the DataObjects that this will list.
* @param class-string<T> $dataClass The class of the DataObjects that this will list.
* @param string $foreignField The name of the composite foreign relation field. Used
* to generate the ID and Class foreign keys.
* @param string $foreignClass Name of the class filter this relation is filtered against
* @param class-string<TForeign> $foreignClass Name of the class filter this relation is filtered against
*/
public function __construct($dataClass, $foreignField, $foreignClass)
{
@ -68,7 +72,7 @@ class PolymorphicHasManyList extends HasManyList
*
* It does so by setting the relationFilters.
*
* @param DataObject|int $item The DataObject to be added, or its ID
* @param T|int $item The DataObject to be added, or its ID
*/
public function add($item)
{
@ -110,7 +114,7 @@ class PolymorphicHasManyList extends HasManyList
* Remove an item from this relation.
* Doesn't actually remove the item, it just clears the foreign key value.
*
* @param DataObject $item The DataObject to be removed
* @param T $item The DataObject to be removed
*/
public function remove($item)
{

View File

@ -12,6 +12,12 @@ use SilverStripe\ORM\FieldType\DBField;
* @method Relation relation($relationName)
* @method Relation forForeignID($id)
* @method string dataClass()
*
* @template T
* @extends SS_List<T>
* @extends Filterable<T>
* @extends Sortable<T>
* @extends Limitable<T>
*/
interface Relation extends SS_List, Filterable, Sortable, Limitable
{

View File

@ -10,6 +10,10 @@ use SilverStripe\ORM\DB;
* A DataList that represents a relation.
*
* Adds the notion of a foreign ID that can be optionally set.
*
* @template T of DataObject
* @extends DataList<T>
* @implements Relation<T>
*/
abstract class RelationList extends DataList implements Relation
{
@ -34,8 +38,6 @@ abstract class RelationList extends DataList implements Relation
* every time they're called.
*
* Note that subclasses of RelationList must implement the callback for it to function
*
* @return this
*/
public function addCallbacks(): CallbackList
{
@ -75,8 +77,6 @@ abstract class RelationList extends DataList implements Relation
* when adding records to this list.
*
* Subclasses of RelationList must implement the callback for it to function
*
* @return this
*/
public function removeCallbacks(): CallbackList
{
@ -118,7 +118,7 @@ abstract class RelationList extends DataList implements Relation
*
* @param int|array $id An ID or an array of IDs.
*
* @return static
* @return static<T>
*/
public function forForeignID($id)
{

View File

@ -8,6 +8,10 @@ use IteratorAggregate;
/**
* An interface that a class can implement to be treated as a list container.
*
* @template T
* @extends ArrayAccess<array-key, T>
* @extends IteratorAggregate<array-key, T>
*/
interface SS_List extends ArrayAccess, Countable, IteratorAggregate
{
@ -15,14 +19,14 @@ interface SS_List extends ArrayAccess, Countable, IteratorAggregate
/**
* Returns all the items in the list in an array.
*
* @return array
* @return array<T>
*/
public function toArray();
/**
* Returns the contents of the list as an array of maps.
*
* @return array
* @return array<T>
*/
public function toNestedArray();
@ -30,28 +34,28 @@ interface SS_List extends ArrayAccess, Countable, IteratorAggregate
* Adds an item to the list, making no guarantees about where it will
* appear.
*
* @param mixed $item
* @param T $item
*/
public function add($item);
/**
* Removes an item from the list.
*
* @param mixed $item
* @param T $item
*/
public function remove($item);
/**
* Returns the first item in the list.
*
* @return mixed
* @return T|null
*/
public function first();
/**
* Returns the last item in the list.
*
* @return mixed
* @return T|null
*/
public function last();
@ -71,7 +75,7 @@ interface SS_List extends ArrayAccess, Countable, IteratorAggregate
*
* @param string $key
* @param mixed $value
* @return mixed
* @return T|null
*/
public function find($key, $value);
@ -87,7 +91,7 @@ interface SS_List extends ArrayAccess, Countable, IteratorAggregate
* Walks the list using the specified callback
*
* @param callable $callback
* @return $this
* @return static<T> $this
*/
public function each($callback);
}

View File

@ -41,6 +41,8 @@ use SilverStripe\ORM\DataQuery;
* to include.
*
* @see http://doc.silverstripe.com/doku.php?id=searchcontext
*
* @template T
*/
class SearchContext
{
@ -50,7 +52,7 @@ class SearchContext
* DataObject subclass to which search parameters relate to.
* Also determines as which object each result is provided.
*
* @var string
* @var class-string<T>
*/
protected $modelClass;
@ -83,7 +85,7 @@ class SearchContext
* in the form of a $_REQUEST object.
* CAUTION: All values should be treated as insecure client input.
*
* @param string $modelClass The base {@link DataObject} class that search properties related to.
* @param class-string<T> $modelClass The base {@link DataObject} class that search properties related to.
* Also used to generate a set of result objects based on this class.
* @param FieldList $fields Optional. FormFields mapping to {@link DataObject::$db} properties
* which are to be searched. Derived from modelclass using
@ -132,7 +134,7 @@ class SearchContext
* Falls back to {@link DataObject::$default_sort} if not provided.
* @param array|null|string $limit
* @param DataList $existingQuery
* @return DataList
* @return DataList<T>
* @throws Exception
*/
public function getQuery($searchParams, $sort = false, $limit = false, $existingQuery = null)
@ -326,7 +328,7 @@ class SearchContext
* @param array $searchParams
* @param array|bool|string $sort
* @param array|null|string $limit
* @return DataList
* @return DataList<T>
* @throws Exception
*/
public function getResults($searchParams, $sort = false, $limit = null)
@ -353,7 +355,7 @@ class SearchContext
* Accessor for the filter attached to a named field.
*
* @param string $name
* @return SearchFilter
* @return SearchFilter|null
*/
public function getFilter($name)
{
@ -377,7 +379,7 @@ class SearchContext
/**
* Overwrite the current search context filter map.
*
* @param array $filters
* @param SearchFilter[] $filters
*/
public function setFilters($filters)
{
@ -448,7 +450,7 @@ class SearchContext
* Set search param values
*
* @param array|HTTPRequest $searchParams
* @return $this
* @return static<T> $this
*/
public function setSearchParams($searchParams)
{

View File

@ -11,6 +11,9 @@ namespace SilverStripe\ORM;
* @see SS_List
* @see Filterable
* @see Limitable
*
* @template T
* @extends SS_List<T>
*/
interface Sortable extends SS_List
{
@ -27,11 +30,12 @@ interface Sortable extends SS_List
* 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.
*
* @return static
* @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<T>
*/
public function sort();
@ -39,8 +43,9 @@ interface Sortable extends SS_List
/**
* Return a new instance of this list based on reversing the current sort.
*
* @return Sortable
* @example $list = $list->reverse();
*
* @return static<T>
*/
public function reverse();
}

View File

@ -17,6 +17,9 @@ use Traversable;
* It can store both saved objects (as IDs) or unsaved objects (as instances
* of $dataClass). Unsaved objects are then written when the list is saved
* into an instance of {@link RelationList}.
*
* @template T of DataObject
* @implements Relation<T>
*/
class UnsavedRelationList extends ArrayList implements Relation
{
@ -38,7 +41,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* The DataObject class name that this relation is querying
*
* @var string
* @var class-string<T>
*/
protected $dataClass;
@ -52,7 +55,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* Create a new UnsavedRelationList
*
* @param string $baseClass
* @param class-string<T> $baseClass
* @param string $relationName
* @param string $dataClass The DataObject class used in the relation
*/
@ -67,7 +70,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* Add an item to this relationship
*
* @param mixed $item
* @param T $item
* @param array $extraFields A map of additional columns to insert into the joinTable in the case of a many_many relation
*/
public function add($item, $extraFields = null)
@ -78,7 +81,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* Save all the items in this list into the RelationList
*
* @param RelationList $list
* @param RelationList<T> $list
*/
public function changeToList(RelationList $list)
{
@ -90,7 +93,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* Pushes an item onto the end of this list.
*
* @param array|object $item
* @param array|T $item
* @param array $extraFields
*/
public function push($item, $extraFields = null)
@ -112,7 +115,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* Get the dataClass name for this relation, ie the DataObject ClassName
*
* @return string
* @return class-string<T>
*/
public function dataClass()
{
@ -121,6 +124,8 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* Returns an Iterator for this relation.
*
* @return iterator<T>
*/
public function getIterator(): Traversable
{
@ -131,7 +136,7 @@ class UnsavedRelationList extends ArrayList implements Relation
* Return an array of the actual items that this relation contains at this stage.
* This is when the query is actually executed.
*
* @return array
* @return array<T>
*/
public function toArray()
{
@ -151,7 +156,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* Add a number of items to the relation.
*
* @param array $items Items to add, as either DataObjects or IDs.
* @param array<T> $items Items to add, as either DataObjects or IDs.
* @return $this
*/
public function addMany($items)
@ -174,7 +179,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* Remove the items from this list with the given IDs
*
* @param array $items
* @param array<T> $items
* @return $this
*/
public function removeMany($items)
@ -233,7 +238,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* Returns the first item in the list
*
* @return mixed
* @return T|null
*/
public function first()
{
@ -250,7 +255,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* Returns the last item in the list
*
* @return mixed
* @return T|null
*/
public function last()
{
@ -287,8 +292,9 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* Returns a copy of this list with the relationship linked to the given foreign ID.
*
* @param int|array $id An ID or an array of IDs.
* @return Relation
* @return Relation<T>
*/
public function forForeignID($id)
{
@ -300,7 +306,7 @@ class UnsavedRelationList extends ArrayList implements Relation
/**
* @param string $relationName
* @return Relation
* @return Relation<T>
*/
public function relation($relationName)
{