silverstripe-framework/model/HasManyList.php
Hamish Friedlander 27113f82c3 API Make DataList and ArrayList immutable
In 3.0 there was some confusion about whether DataLists and ArrayLists
were mutable or not. If DataLists were immutable, they'd return the result, and your code
would look like

  $list = $list->filter(....);

If DataLists were mutable, they'd operate on themselves, returning nothing, and your code
would look like

 $list->filter(....);

This makes all DataLists and ArrayList immutable for all _searching_ operations.
Operations on DataList that modify the underlying SQL data store remain mutating.

- These functions no longer mutate the existing object, and if you do not capture the value
returned by them will have no effect:

  ArrayList#reverse
  ArrayList#sort
  ArrayList#filter
  ArrayList#exclude

  DataList#dataQuery (use DataList#alterDataQuery to modify dataQuery in a safe manner)
  DataList#where
  DataList#limit
  DataList#sort
  DataList#addFilter
  DataList#applyFilterContext
  DataList#innerJoin
  DataList#leftJoin
  DataList#find
  DataList#byIDs
  DataList#reverse

- DataList#setDataQueryParam has been added as syntactic sugar around the most common
cause of accessing the dataQuery directly - setting query parameters

- RelationList#setForeignID has been removed. Always use RelationList#forForeignID
when querying, and overload RelationList#foreignIDList when subclassing.

- Relatedly,the protected variable RelationList->foreignID has been removed, as the ID is
now stored on a query parameter. Use RelationList#getForeignID to read it.
2012-12-14 13:30:35 +13:00

96 lines
2.7 KiB
PHP

<?php
/**
* Subclass of {@link DataList} representing a has_many relation
*/
class HasManyList extends RelationList {
protected $foreignKey;
/**
* Create a new HasManyList object.
* Generation of the appropriate record set is left up to the caller, using the normal
* {@link DataList} methods. Addition arguments are used to support {@@link add()}
* and {@link remove()} methods.
*
* @param $dataClass The class of the DataObjects that this will list.
* @param $relationFilters A map of key => value filters that define which records
* in the $dataClass table actually belong to this relationship.
*/
public function __construct($dataClass, $foreignKey) {
parent::__construct($dataClass);
$this->foreignKey = $foreignKey;
}
protected function foreignIDFilter($id = null) {
if ($id === null) $id = $this->getForeignID();
// Apply relation filter
if(is_array($id)) {
return "\"$this->foreignKey\" IN ('" .
implode("', '", array_map('Convert::raw2sql', $id)) . "')";
} else if($id !== null){
return "\"$this->foreignKey\" = '" .
Convert::raw2sql($id) . "'";
}
}
/**
* Adds the item to this relation.
* It does so by setting the relationFilters.
* @param $item The DataObject to be added, or its ID
*/
public function add($item) {
if(is_numeric($item)) {
$item = DataObject::get_by_id($this->dataClass, $item);
} else if(!($item instanceof $this->dataClass)) {
user_error("HasManyList::add() expecting a $this->dataClass object, or ID value", E_USER_ERROR);
}
$foreignID = $this->getForeignID();
// Validate foreignID
if(!$foreignID) {
user_error("ManyManyList::add() can't be called until a foreign ID is set", E_USER_WARNING);
return;
}
if(is_array($foreignID)) {
user_error("ManyManyList::add() can't be called on a list linked to mulitple foreign IDs", E_USER_WARNING);
return;
}
$fk = $this->foreignKey;
$item->$fk = $foreignID;
$item->write();
}
/**
* Remove an item from this relation.
* Doesn't actually remove the item, it just clears the foreign key value.
* @param $itemID The ID of the item to be removed
*/
public function removeByID($itemID) {
$item = $this->byID($itemID);
return $this->remove($item);
}
/**
* Remove an item from this relation.
* Doesn't actually remove the item, it just clears the foreign key value.
* @param $item The DataObject to be removed
* @todo Maybe we should delete the object instead?
*/
public function remove($item) {
if(!($item instanceof $this->dataClass)) {
throw new InvalidArgumentException("HasManyList::remove() expecting a $this->dataClass object, or ID",
E_USER_ERROR);
}
$fk = $this->foreignKey;
$item->$fk = null;
$item->write();
}
}