mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
NEW: Allows setting of has_many and many_many relations before writing
Adds a new wrapper list, UnsavedRelationList, that maintains the relations until writing, where it is converted into the correct RelationList.
This commit is contained in:
parent
fbfff8df28
commit
bbc4443af7
@ -553,13 +553,25 @@ See `[api:DataObject::$has_many]` for more info on the described relations.
|
|||||||
|
|
||||||
// can be accessed by $myTeam->ActivePlayers()
|
// can be accessed by $myTeam->ActivePlayers()
|
||||||
public function ActivePlayers() {
|
public function ActivePlayers() {
|
||||||
return $this->Players("Status='Active'");
|
return $this->Players()->filter('Status', 'Active');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Note: Adding new records to a filtered `RelationList` like in the example above doesn't automatically set the
|
Note: Adding new records to a filtered `RelationList` like in the example above doesn't automatically set the
|
||||||
filtered criteria on the added record.
|
filtered criteria on the added record.
|
||||||
|
|
||||||
|
### Relations on Unsaved Objects
|
||||||
|
|
||||||
|
You can also set *has_many* and *many_many* relations before the `DataObject` is saved. This behaviour uses the
|
||||||
|
`[api:UnsavedRelationList]` and converts it into the correct `RelationList` when saving the `DataObject` for the
|
||||||
|
first time.
|
||||||
|
|
||||||
|
This unsaved lists will also recursively save any unsaved objects that they contain.
|
||||||
|
|
||||||
|
As these lists are not backed by the database, most of the filtering methods on `DataList` cannot be used on a
|
||||||
|
list of this type. As such, an `UnsavedRelationList` should only be used for setting a relation before saving an
|
||||||
|
object, not for displaying the objects contained in the relation.
|
||||||
|
|
||||||
## Validation and Constraints
|
## Validation and Constraints
|
||||||
|
|
||||||
Traditionally, validation in SilverStripe has been mostly handled on the controller
|
Traditionally, validation in SilverStripe has been mostly handled on the controller
|
||||||
|
@ -12,7 +12,7 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $items;
|
protected $items = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -157,6 +157,11 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
*/
|
*/
|
||||||
protected $components;
|
protected $components;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-static cache of has_many and many_many relations that can't be written until this object is saved.
|
||||||
|
*/
|
||||||
|
protected $unsavedRelations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns when validation on DataObjects is enabled.
|
* Returns when validation on DataObjects is enabled.
|
||||||
* @return bool
|
* @return bool
|
||||||
@ -1188,6 +1193,15 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
DB::manipulate($manipulation);
|
DB::manipulate($manipulation);
|
||||||
|
|
||||||
|
// If there's any relations that couldn't be saved before, save them now (we have an ID here)
|
||||||
|
if($this->unsavedRelations) {
|
||||||
|
foreach($this->unsavedRelations as $name => $list) {
|
||||||
|
$list->changeToList($this->$name());
|
||||||
|
}
|
||||||
|
$this->unsavedRelations = array();
|
||||||
|
}
|
||||||
|
|
||||||
$this->onAfterWrite();
|
$this->onAfterWrite();
|
||||||
|
|
||||||
$this->changed = null;
|
$this->changed = null;
|
||||||
@ -1365,6 +1379,15 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
. " on class '$this->class'", E_USER_ERROR);
|
. " on class '$this->class'", E_USER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we haven't been written yet, we can't save these relations, so use a list that handles this case
|
||||||
|
if(!$this->ID) {
|
||||||
|
if(!isset($this->unsavedRelations[$componentName])) {
|
||||||
|
$this->unsavedRelations[$componentName] =
|
||||||
|
new UnsavedRelationList($this->class, $componentName, $componentClass);
|
||||||
|
}
|
||||||
|
return $this->unsavedRelations[$componentName];
|
||||||
|
}
|
||||||
|
|
||||||
$joinField = $this->getRemoteJoinField($componentName, 'has_many');
|
$joinField = $this->getRemoteJoinField($componentName, 'has_many');
|
||||||
|
|
||||||
$result = new HasManyList($componentClass, $joinField);
|
$result = new HasManyList($componentClass, $joinField);
|
||||||
@ -1474,6 +1497,15 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
public function getManyManyComponents($componentName, $filter = "", $sort = "", $join = "", $limit = "") {
|
public function getManyManyComponents($componentName, $filter = "", $sort = "", $join = "", $limit = "") {
|
||||||
list($parentClass, $componentClass, $parentField, $componentField, $table) = $this->many_many($componentName);
|
list($parentClass, $componentClass, $parentField, $componentField, $table) = $this->many_many($componentName);
|
||||||
|
|
||||||
|
// If we haven't been written yet, we can't save these relations, so use a list that handles this case
|
||||||
|
if(!$this->ID) {
|
||||||
|
if(!isset($this->unsavedRelations[$componentName])) {
|
||||||
|
$this->unsavedRelations[$componentName] =
|
||||||
|
new UnsavedRelationList($parentClass, $componentName, $componentClass);
|
||||||
|
}
|
||||||
|
return $this->unsavedRelations[$componentName];
|
||||||
|
}
|
||||||
|
|
||||||
$result = Injector::inst()->create('ManyManyList', $componentClass, $table, $componentField, $parentField,
|
$result = Injector::inst()->create('ManyManyList', $componentClass, $table, $componentField, $parentField,
|
||||||
$this->many_many_extraFields($componentName));
|
$this->many_many_extraFields($componentName));
|
||||||
if($this->model) $result->setDataModel($this->model);
|
if($this->model) $result->setDataModel($this->model);
|
||||||
|
432
model/UnsavedRelationList.php
Normal file
432
model/UnsavedRelationList.php
Normal file
@ -0,0 +1,432 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ArrayList that represents an unsaved relation.
|
||||||
|
*
|
||||||
|
* has_many and many_many relations cannot be saved until after the DataObject they're
|
||||||
|
* on has been written. This List pretends to be a RelationList and stores the related
|
||||||
|
* objects in memory.
|
||||||
|
*
|
||||||
|
* 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 RelationList.
|
||||||
|
*
|
||||||
|
* Most methods that alter the list of objects throw LogicExceptions.
|
||||||
|
*/
|
||||||
|
class UnsavedRelationList extends ArrayList {
|
||||||
|
/**
|
||||||
|
* The DataObject class name that this relation is on
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $baseClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the relation
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $relationName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DataObject class name that this relation is querying
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $dataClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The extra fields associated with the relation
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $extraFields = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new UnsavedRelationList
|
||||||
|
*
|
||||||
|
* @param string $dataClass The DataObject class used in the relation
|
||||||
|
*/
|
||||||
|
public function __construct($baseClass, $relationName, $dataClass) {
|
||||||
|
$this->baseClass = $baseClass;
|
||||||
|
$this->relationName = $relationName;
|
||||||
|
$this->dataClass = $dataClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an item to this relationship
|
||||||
|
*
|
||||||
|
* @param $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) {
|
||||||
|
$this->push($item, $extraFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save all the items in this list into the RelationList
|
||||||
|
*
|
||||||
|
* @param RelationList $list
|
||||||
|
*/
|
||||||
|
public function changeToList(RelationList $list) {
|
||||||
|
foreach($this->items as $key => $item) {
|
||||||
|
if(is_object($item)) {
|
||||||
|
$item->write();
|
||||||
|
}
|
||||||
|
$list->add($item, $this->extraFields[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes an item onto the end of this list.
|
||||||
|
*
|
||||||
|
* @param array|object $item
|
||||||
|
*/
|
||||||
|
public function push($item, $extraFields = null) {
|
||||||
|
if((is_object($item) && !$item instanceof $this->dataClass)
|
||||||
|
|| (!is_object($item) && !is_numeric($item))) {
|
||||||
|
throw new InvalidArgumentException(
|
||||||
|
"UnsavedRelationList::add() expecting a $this->dataClass object, or ID value",
|
||||||
|
E_USER_ERROR);
|
||||||
|
}
|
||||||
|
if(is_object($item) && $item->ID) {
|
||||||
|
$item = $item->ID;
|
||||||
|
}
|
||||||
|
$this->extraFields[] = $extraFields;
|
||||||
|
parent::push($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the dataClass name for this relation, ie the DataObject ClassName
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function dataClass() {
|
||||||
|
return $this->dataClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an Iterator for this relation.
|
||||||
|
*
|
||||||
|
* @return ArrayIterator
|
||||||
|
*/
|
||||||
|
public function getIterator() {
|
||||||
|
return new ArrayIterator($this->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array of the actual items that this relation contains at this stage.
|
||||||
|
* This is when the query is actually executed.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray() {
|
||||||
|
$items = array();
|
||||||
|
foreach($this->items as $key => $item) {
|
||||||
|
if(is_numeric($item)) {
|
||||||
|
$item = DataObject::get_by_id($this->dataClass, $item);
|
||||||
|
}
|
||||||
|
if(!empty($this->extraFields[$key])) {
|
||||||
|
$item->update($this->extraFields[$key]);
|
||||||
|
}
|
||||||
|
$items[] = $item;
|
||||||
|
}
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a number of items to the relation.
|
||||||
|
*
|
||||||
|
* @param array $items Items to add, as either DataObjects or IDs.
|
||||||
|
* @return DataList
|
||||||
|
*/
|
||||||
|
public function addMany($items) {
|
||||||
|
foreach($items as $item) {
|
||||||
|
$this->add($item);
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given column can be used to filter the records.
|
||||||
|
*/
|
||||||
|
public function canFilterBy($by) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given column can be used to sort the records.
|
||||||
|
*/
|
||||||
|
public function canSortBy($by) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all items from this relation.
|
||||||
|
*/
|
||||||
|
public function removeAll() {
|
||||||
|
$this->items = array();
|
||||||
|
$this->extraFields = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the items from this list with the given IDs
|
||||||
|
*
|
||||||
|
* @param array $idList
|
||||||
|
*/
|
||||||
|
public function removeMany($items) {
|
||||||
|
$this->items = array_diff($this->items, $items);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes items from this list which are equal.
|
||||||
|
*
|
||||||
|
* @param string $field unused
|
||||||
|
*/
|
||||||
|
public function removeDuplicates($field = 'ID') {
|
||||||
|
$this->items = array_unique($this->items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Relation to be the given ID list.
|
||||||
|
* Records will be added and deleted as appropriate.
|
||||||
|
*
|
||||||
|
* @param array $idList List of IDs.
|
||||||
|
*/
|
||||||
|
public function setByIDList($idList) {
|
||||||
|
$this->removeAll();
|
||||||
|
$this->addMany($idList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first item in the list
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function first() {
|
||||||
|
$item = reset($this->items);
|
||||||
|
if(is_numeric($item)) {
|
||||||
|
$item = DataObject::get_by_id($this->dataClass, $item);
|
||||||
|
}
|
||||||
|
if(!empty($this->extraFields[key($this->items)])) {
|
||||||
|
$item->update($this->extraFields[key($this->items)]);
|
||||||
|
}
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last item in the list
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function last() {
|
||||||
|
$item = end($this->items);
|
||||||
|
if(!empty($this->extraFields[key($this->items)])) {
|
||||||
|
$item->update($this->extraFields[key($this->items)]);
|
||||||
|
}
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of a single field value for all items in the list.
|
||||||
|
*
|
||||||
|
* @param string $colName
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function column($colName = 'ID') {
|
||||||
|
$list = new ArrayList($this->toArray());
|
||||||
|
return $list->column('ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the ID of the record that this RelationList is linking.
|
||||||
|
*
|
||||||
|
* Adds the
|
||||||
|
*
|
||||||
|
* @param $id A single ID, or an array of IDs
|
||||||
|
*/
|
||||||
|
public function setForeignID($id) {
|
||||||
|
$class = singleton($this->baseClass);
|
||||||
|
$class->ID = 1;
|
||||||
|
return $class->{$this->relationName}()->setForeignID($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this list with the relationship linked to the given foreign ID.
|
||||||
|
* @param $id An ID or an array of IDs.
|
||||||
|
*/
|
||||||
|
public function forForeignID($id) {
|
||||||
|
return $this->setForeignID($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the DBField object that represents the given field on the related class.
|
||||||
|
*
|
||||||
|
* @param string $fieldName Name of the field
|
||||||
|
* @return DBField The field as a DBField object
|
||||||
|
*/
|
||||||
|
public function dbObject($fieldName) {
|
||||||
|
return singleton($this->dataClass)->dbObject($fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**#@+
|
||||||
|
* Prevents calling DataList methods that rely on the objects being saved
|
||||||
|
*/
|
||||||
|
public function addFilter() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterDataQuery() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function avg() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function byIDs() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function byID($id) {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataQuery() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exclude() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function filter() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIDList() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRange($offset, $length) {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelationName() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function innerJoin() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insertFirst() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function join() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function leftJoin() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function limit($length, $offset = 0) {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function map($keyField = 'ID', $titleField = 'Title') {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function max() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function merge($with) {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function min() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetExists($offset) {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetGet($offset) {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetSet($offset, $value) {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetUnset($offset) {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pop() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function relation() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeByFilter() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeByID() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reverse() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDataModel() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDataQuery() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setQueriedColumns() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shift() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sql() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function subtract() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sum() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unshift($item) {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function where() {
|
||||||
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
|
}
|
||||||
|
/**#@-*/
|
||||||
|
}
|
184
tests/model/UnsavedRelationListTest.php
Normal file
184
tests/model/UnsavedRelationListTest.php
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class UnsavedRelationListTest extends SapphireTest {
|
||||||
|
public static $fixture_file = 'UnsavedRelationListTest.yml';
|
||||||
|
|
||||||
|
protected $extraDataObjects = array('UnsavedRelationListTest_DataObject');
|
||||||
|
|
||||||
|
public function testReturnedList() {
|
||||||
|
$object = new UnsavedRelationListTest_DataObject;
|
||||||
|
$children = $object->Children();
|
||||||
|
$siblings = $object->Siblings();
|
||||||
|
$this->assertEquals($children, $object->Children(),
|
||||||
|
'Returned UnsavedRelationList should be the same.');
|
||||||
|
$this->assertEquals($siblings, $object->Siblings(),
|
||||||
|
'Returned UnsavedRelationList should be the same.');
|
||||||
|
|
||||||
|
$object->write();
|
||||||
|
$this->assertInstanceOf('RelationList', $object->Children());
|
||||||
|
$this->assertNotEquals($children, $object->Children(),
|
||||||
|
'Return should be a RelationList after first write');
|
||||||
|
$this->assertInstanceOf('RelationList', $object->Siblings());
|
||||||
|
$this->assertNotEquals($siblings, $object->Siblings(),
|
||||||
|
'Return should be a RelationList after first write');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHasManyExisting() {
|
||||||
|
$object = new UnsavedRelationListTest_DataObject;
|
||||||
|
|
||||||
|
$children = $object->Children();
|
||||||
|
$children->add($this->objFromFixture('UnsavedRelationListTest_DataObject', 'ObjectA'));
|
||||||
|
$children->add($this->objFromFixture('UnsavedRelationListTest_DataObject', 'ObjectB'));
|
||||||
|
$children->add($this->objFromFixture('UnsavedRelationListTest_DataObject', 'ObjectC'));
|
||||||
|
|
||||||
|
$children = $object->Children();
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array('Name' => 'A'),
|
||||||
|
array('Name' => 'B'),
|
||||||
|
array('Name' => 'C')
|
||||||
|
), $children);
|
||||||
|
|
||||||
|
$object->write();
|
||||||
|
|
||||||
|
$this->assertNotEquals($children, $object->Children());
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array('Name' => 'A'),
|
||||||
|
array('Name' => 'B'),
|
||||||
|
array('Name' => 'C')
|
||||||
|
), $object->Children());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testManyManyExisting() {
|
||||||
|
$object = new UnsavedRelationListTest_DataObject;
|
||||||
|
|
||||||
|
$Siblings = $object->Siblings();
|
||||||
|
$Siblings->add($this->objFromFixture('UnsavedRelationListTest_DataObject', 'ObjectA'));
|
||||||
|
$Siblings->add($this->objFromFixture('UnsavedRelationListTest_DataObject', 'ObjectB'));
|
||||||
|
$Siblings->add($this->objFromFixture('UnsavedRelationListTest_DataObject', 'ObjectC'));
|
||||||
|
|
||||||
|
$siblings = $object->Siblings();
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array('Name' => 'A'),
|
||||||
|
array('Name' => 'B'),
|
||||||
|
array('Name' => 'C')
|
||||||
|
), $siblings);
|
||||||
|
|
||||||
|
$object->write();
|
||||||
|
|
||||||
|
$this->assertNotEquals($siblings, $object->Siblings());
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array('Name' => 'A'),
|
||||||
|
array('Name' => 'B'),
|
||||||
|
array('Name' => 'C')
|
||||||
|
), $object->Siblings());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHasManyNew() {
|
||||||
|
$object = new UnsavedRelationListTest_DataObject;
|
||||||
|
|
||||||
|
$children = $object->Children();
|
||||||
|
$children->add(new UnsavedRelationListTest_DataObject(array('Name' => 'A')));
|
||||||
|
$children->add(new UnsavedRelationListTest_DataObject(array('Name' => 'B')));
|
||||||
|
$children->add(new UnsavedRelationListTest_DataObject(array('Name' => 'C')));
|
||||||
|
|
||||||
|
$children = $object->Children();
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array('Name' => 'A'),
|
||||||
|
array('Name' => 'B'),
|
||||||
|
array('Name' => 'C')
|
||||||
|
), $children);
|
||||||
|
|
||||||
|
$object->write();
|
||||||
|
|
||||||
|
$this->assertNotEquals($children, $object->Children());
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array('Name' => 'A'),
|
||||||
|
array('Name' => 'B'),
|
||||||
|
array('Name' => 'C')
|
||||||
|
), $object->Children());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testManyManyNew() {
|
||||||
|
$object = new UnsavedRelationListTest_DataObject;
|
||||||
|
|
||||||
|
$Siblings = $object->Siblings();
|
||||||
|
$Siblings->add(new UnsavedRelationListTest_DataObject(array('Name' => 'A')));
|
||||||
|
$Siblings->add(new UnsavedRelationListTest_DataObject(array('Name' => 'B')));
|
||||||
|
$Siblings->add(new UnsavedRelationListTest_DataObject(array('Name' => 'C')));
|
||||||
|
|
||||||
|
$siblings = $object->Siblings();
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array('Name' => 'A'),
|
||||||
|
array('Name' => 'B'),
|
||||||
|
array('Name' => 'C')
|
||||||
|
), $siblings);
|
||||||
|
|
||||||
|
$object->write();
|
||||||
|
|
||||||
|
$this->assertNotEquals($siblings, $object->Siblings());
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array('Name' => 'A'),
|
||||||
|
array('Name' => 'B'),
|
||||||
|
array('Name' => 'C')
|
||||||
|
), $object->Siblings());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testManyManyExtraFields() {
|
||||||
|
$object = new UnsavedRelationListTest_DataObject;
|
||||||
|
|
||||||
|
$Siblings = $object->Siblings();
|
||||||
|
$Siblings->add(new UnsavedRelationListTest_DataObject(array('Name' => 'A')), array('Number' => 1));
|
||||||
|
$Siblings->add(new UnsavedRelationListTest_DataObject(array('Name' => 'B')), array('Number' => 2));
|
||||||
|
$Siblings->add(new UnsavedRelationListTest_DataObject(array('Name' => 'C')), array('Number' => 3));
|
||||||
|
|
||||||
|
$siblings = $object->Siblings();
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array('Name' => 'A', 'Number' => 1),
|
||||||
|
array('Name' => 'B', 'Number' => 2),
|
||||||
|
array('Name' => 'C', 'Number' => 3)
|
||||||
|
), $siblings);
|
||||||
|
|
||||||
|
$object->write();
|
||||||
|
|
||||||
|
$this->assertNotEquals($siblings, $object->Siblings());
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array('Name' => 'A', 'Number' => 1),
|
||||||
|
array('Name' => 'B', 'Number' => 2),
|
||||||
|
array('Name' => 'C', 'Number' => 3)
|
||||||
|
), $object->Siblings());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnsavedRelationListTest_DataObject extends DataObject implements TestOnly {
|
||||||
|
public static $db = array(
|
||||||
|
'Name' => 'Varchar',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $has_one = array(
|
||||||
|
'Parent' => 'UnsavedRelationListTest_DataObject',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $has_many = array(
|
||||||
|
'Children' => 'UnsavedRelationListTest_DataObject',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $many_many = array(
|
||||||
|
'Siblings' => 'UnsavedRelationListTest_DataObject',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $many_many_extraFields = array(
|
||||||
|
'Siblings' => array(
|
||||||
|
'Number' => 'Int',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
7
tests/model/UnsavedRelationListTest.yml
Normal file
7
tests/model/UnsavedRelationListTest.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
UnsavedRelationListTest_DataObject:
|
||||||
|
ObjectA:
|
||||||
|
Name: A
|
||||||
|
ObjectB:
|
||||||
|
Name: B
|
||||||
|
ObjectC:
|
||||||
|
Name: C
|
Loading…
Reference in New Issue
Block a user