Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 295 lines (257 sloc) 8.312 kb
<?php
/**
* This is a special kind of DataObjectSet used to represent the items linked to in a 1-many or many-many
* join. It provides add and remove methods that will update the database.
* @package sapphire
* @subpackage model
*/
class ComponentSet extends DataObjectSet {
/**
* Type of relationship (eg '1-1', '1-many').
* @var string
*/
protected $type;
/**
* Object that owns this set.
* @var DataObject
*/
protected $ownerObj;
/**
* Class of object that owns this set.
* @var string
*/
protected $ownerClass;
/**
* Table that holds this relationship.
* @var string
*/
protected $tableName;
/**
* Class of child side of the relationship.
* @var string
*/
protected $childClass;
/**
* Field to join on.
* @var string
*/
protected $joinField;
/**
* Set the ComponentSet specific information.
* @param string $type Type of relationship (eg '1-1', '1-many').
* @param DataObject $ownerObj Object that owns this set.
* @param string $ownerClass Class of object that owns this set.
* @param string $tableName Table that holds this relationship.
* @param string $childClass Class of child side of the relationship.
* @param string $joinField Field to join on.
*/
function setComponentInfo($type, $ownerObj, $ownerClass, $tableName, $childClass, $joinField = null) {
$this->type = $type;
$this->ownerObj = $ownerObj;
$this->ownerClass = $ownerClass ? $ownerClass : $ownerObj->class;
$this->tableName = $tableName;
$this->childClass = $childClass;
$this->joinField = $joinField;
}
/**
* Get an array of all the IDs in this component set, where the keys are the same as the
* values.
* @return array
*/
function getIdList() {
$list = array();
foreach($this->items as $item) {
$list[$item->ID] = $item->ID;
}
return $list;
}
/**
* Add an item to this set.
* @param DataObject|int|string $item Item to add, either as a DataObject or as the ID.
* @param array $extraFields A map of extra fields to add.
*/
function add($item, $extraFields = null) {
if(!isset($item)) {
user_error("ComponentSet::add() Not passed an object or ID", E_USER_ERROR);
}
if(is_object($item)) {
if(!is_a($item, $this->childClass)) {
user_error("ComponentSet::add() Tried to add an '{$item->class}' object, but a '{$this->childClass}' object expected", E_USER_ERROR);
}
} else {
$id = $item;
if(!$this->childClass) {
user_error("ComponentSet::add() \$this->childClass not set", E_USER_ERROR);
}
$item = DataObject::get_by_id($this->childClass, $item);
if(!$item) return;
}
// If we've already got a database object, then update the database
if($this->ownerObj->ID && is_numeric($this->ownerObj->ID)) {
$this->loadChildIntoDatabase($item, $extraFields);
}
// In either case, add something to $this->items
$this->items[] = $item;
}
/**
* Method to save many-many join data into the database for the given $item.
* Used by add() and write().
* @param DataObject|string|int The item to save, as either a DataObject or the ID.
* @param array $extraFields Map of extra fields.
*/
protected function loadChildIntoDatabase($item, $extraFields = null) {
if($this->type == '1-to-many') {
$child = DataObject::get_by_id($this->childClass,$item->ID);
if (!$child) $child = $item;
$joinField = $this->joinField;
$child->$joinField = $this->ownerObj->ID;
$child->write();
} else {
$parentField = $this->ownerClass . 'ID';
$childField = ($this->childClass == $this->ownerClass) ? "ChildID" : ($this->childClass . 'ID');
DB::query( "DELETE FROM `$this->tableName` WHERE $parentField = {$this->ownerObj->ID} AND $childField = {$item->ID}" );
$extraSQL = '';
if($extraFields) foreach($extraFields as $k => $v) {
$extraSQL .= ", $k = '" . Convert::raw2sql($v) . "'";
}
DB::query("INSERT INTO `$this->tableName` SET $parentField = {$this->ownerObj->ID}, $childField = {$item->ID} $extraSQL");
}
}
/**
* Add a number of items to the component set.
* @param array $items Items to add, as either DataObjects or IDs.
*/
function addMany($items) {
foreach($items as $item) {
$this->add($item);
}
}
/**
* Sets the ComponentSet to be the given ID list.
* Records will be added and deleted as appropriate.
* @param array $idList List of IDs.
*/
function setByIDList($idList) {
$has = array();
// Index current data
if($this->items) foreach($this->items as $item) {
$has[$item->ID] = true;
}
// Keep track of items to delete
$itemsToDelete = $has;
// add items in the list
// $id is the database ID of the record
if($idList) foreach($idList as $id) {
$itemsToDelete[$id] = false;
if($id && !isset($has[$id])) $this->add($id);
}
// delete items not in the list
$removeList = array();
foreach($itemsToDelete as $id => $actuallyDelete) {
if($actuallyDelete) $removeList[] = $id;
}
$this->removeMany($removeList);
}
/**
* Remove an item from this set.
*
* @param DataObject|string|int $item Item to remove, either as a DataObject or as the ID.
*/
function remove($item) {
if(is_object($item)) {
if(!is_a($item, $this->childClass)) {
user_error("ComponentSet::remove() Tried to remove an '{$item->class}' object, but a '{$this->childClass}' object expected", E_USER_ERROR);
}
} else {
$item = DataObject::get_by_id($this->childClass, $item);
}
// Manipulate the database, if it's in there
if($this->ownerObj->ID && is_numeric($this->ownerObj->ID)) {
if($this->type == '1-to-many') {
$child = DataObject::get_by_id($this->childClass,$item->ID);
$joinField = $this->joinField;
if($child->$joinField == $this->ownerObj->ID) {
$child->$joinField = null;
$child->write();
}
} else {
$parentField = $this->ownerClass . 'ID';
$childField = ($this->childClass == $this->ownerClass) ? "ChildID" : ($this->childClass . 'ID');
DB::query("DELETE FROM `$this->tableName` WHERE $parentField = {$this->ownerObj->ID} AND $childField = {$item->ID}");
}
}
// Manipulate the in-memory array of items
if($this->items) foreach($this->items as $i => $candidateItem) {
if($candidateItem->ID == $item->ID) {
unset($this->items[$i]);
break;
}
}
}
/**
* Remove many items from this set.
* @param array $itemList The items to remove, as a numerical array with IDs or as a DataObjectSet
*/
function removeMany($itemList) {
if(!count($itemList)) return false;
if($this->type == '1-to-many') {
foreach($itemList as $item) $this->remove($item);
} else {
$itemCSV = implode(", ", $itemList);
$parentField = $this->ownerClass . 'ID';
$childField = ($this->childClass == $this->ownerClass) ? "ChildID" : ($this->childClass . 'ID');
DB::query("DELETE FROM `$this->tableName` WHERE $parentField = {$this->ownerObj->ID} AND $childField IN ($itemCSV)");
}
}
/**
* Remove all items that match the SQL filter.
* @deprecated 2.3 Not flexible enough, use custom code
* @param string $filter Filter to be inserted into the WHERE clause
*/
function removeByFilter($filter) {
$parentField = $this->ownerClass . 'ID';
DB::query("DELETE FROM `$this->tableName` WHERE $parentField = {$this->ownerObj->ID} AND $filter");
}
/**
* Remove all items in this set.
*/
function removeAll() {
if(!empty($this->tableName)) {
$parentField = $this->ownerClass . 'ID';
DB::query("DELETE FROM `$this->tableName` WHERE $parentField = {$this->ownerObj->ID}");
} else {
foreach($this->items as $item) {
$this->remove($item);
}
}
}
/**
* Write this set to the database.
* Called by DataObject::write().
* @param boolean $firstWrite This should be set to true if it the first time the set is being written.
*/
function write($firstWrite = false) {
if($firstWrite) {
foreach($this->items as $item) {
$this->loadChildIntoDatabase($item);
}
}
}
/**
* Returns information about this set in HTML format for debugging.
*
* @return string
*/
function debug() {
$size = count($this->items);
$output = <<<OUT
<h3>ComponentSet</h3>
<ul>
<li>Type: {$this->type}</li>
<li>Size: $size</li>
</ul>
OUT;
return $output;
}
}
?>
Jump to Line
Something went wrong with that request. Please try again.