mlantahler:Bugfix: Added checks in DataObjectSet::First() and DataObjectSet::Last() to prevent errors on an empty $items array. (merged from branches/gsoc)

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@41778 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2007-09-14 17:59:33 +00:00
parent 898d897c9e
commit d47e6cf67c

View File

@ -75,7 +75,7 @@ class DataObjectSet extends ViewableData implements Iterator {
} }
parent::__construct(); parent::__construct();
} }
/** /**
* Consolidate the DataObjectSet into an array of arrays * Consolidate the DataObjectSet into an array of arrays
* The array will contain the field values of the specified fields * The array will contain the field values of the specified fields
@ -91,7 +91,7 @@ class DataObjectSet extends ViewableData implements Iterator {
} }
$output[] = $outputRow; $output[] = $outputRow;
} }
return $output; return $output;
} }
/** /**
@ -102,7 +102,7 @@ class DataObjectSet extends ViewableData implements Iterator {
public function consolidateString() { public function consolidateString() {
$fieldList = func_get_args(); $fieldList = func_get_args();
$data = $this->consolidate($fieldList); $data = $this->consolidate($fieldList);
$result = "<p>array (<br >"; $result = "<p>array (<br >";
foreach($data as $record) { foreach($data as $record) {
$result .= " &nbsp; &nbsp; array( "; $result .= " &nbsp; &nbsp; array( ";
@ -140,7 +140,7 @@ class DataObjectSet extends ViewableData implements Iterator {
return $map; return $map;
} }
/** /**
* Convert this DataObjectSet to an array of maps. * Convert this DataObjectSet to an array of maps.
* @param string $index Index the array by this field. * @param string $index Index the array by this field.
@ -159,7 +159,7 @@ class DataObjectSet extends ViewableData implements Iterator {
return $map; return $map;
} }
/** /**
* Returns an array of ID => $titleField * Returns an array of ID => $titleField
* @param string $index The field you wish to use as a key for the array * @param string $index The field you wish to use as a key for the array
@ -197,7 +197,7 @@ class DataObjectSet extends ViewableData implements Iterator {
$this->pageLength = $pageLength; $this->pageLength = $pageLength;
$this->totalSize = $totalSize; $this->totalSize = $totalSize;
} }
/** /**
* Use the limit from the given query to add prev/next buttons to this DataObjectSet. * Use the limit from the given query to add prev/next buttons to this DataObjectSet.
* @param SQLQuery $query The query used to generate this DataObjectSet * @param SQLQuery $query The query used to generate this DataObjectSet
@ -242,7 +242,7 @@ class DataObjectSet extends ViewableData implements Iterator {
return ceil($this->totalSize / $this->pageLength); return ceil($this->totalSize / $this->pageLength);
} }
/** /**
* Return a datafeed of page-links, good for use in search results, etc. * Return a datafeed of page-links, good for use in search results, etc.
* $maxPages will put an upper limit on the number of pages to return. It will * $maxPages will put an upper limit on the number of pages to return. It will
@ -252,11 +252,11 @@ class DataObjectSet extends ViewableData implements Iterator {
*/ */
public function Pages($maxPages = 0){ public function Pages($maxPages = 0){
$ret = new DataObjectSet(); $ret = new DataObjectSet();
if($maxPages) { if($maxPages) {
$startPage = ($this->CurrentPage() - floor($maxPages / 2)) - 1; $startPage = ($this->CurrentPage() - floor($maxPages / 2)) - 1;
$endPage = $this->CurrentPage() + floor($maxPages / 2); $endPage = $this->CurrentPage() + floor($maxPages / 2);
if($startPage < 0) { if($startPage < 0) {
$startPage = 0; $startPage = 0;
$endPage = $maxPages; $endPage = $maxPages;
@ -265,7 +265,7 @@ class DataObjectSet extends ViewableData implements Iterator {
$endPage = $this->TotalPages(); $endPage = $this->TotalPages();
$startPage = max(0, $endPage - $maxPages); $startPage = max(0, $endPage - $maxPages);
} }
} else { } else {
$startPage = 0; $startPage = 0;
$endPage = $this->TotalPages(); $endPage = $this->TotalPages();
@ -328,17 +328,17 @@ class DataObjectSet extends ViewableData implements Iterator {
return HTTP::setGetVar($this->paginationGetVar, $this->pageStart + $this->pageLength); return HTTP::setGetVar($this->paginationGetVar, $this->pageStart + $this->pageLength);
} }
} }
/** /**
* Allows us to use multiple pagination GET variables on the same page (eg. if you have search results and page comments on a single page) * Allows us to use multiple pagination GET variables on the same page (eg. if you have search results and page comments on a single page)
* *
* Example: @see PageCommentInterface::Comments() * Example: @see PageCommentInterface::Comments()
* @param string $var The variable to go in the GET string (Defaults to 'start') * @param string $var The variable to go in the GET string (Defaults to 'start')
*/ */
public function setPaginationGetVar($var) { public function setPaginationGetVar($var) {
$this->paginationGetVar = $var; $this->paginationGetVar = $var;
} }
/** /**
* Add an item to the DataObject Set. * Add an item to the DataObject Set.
* @param DataObject $item Item to add. * @param DataObject $item Item to add.
@ -375,7 +375,7 @@ class DataObjectSet extends ViewableData implements Iterator {
*/ */
public function append(DataObjectSet $doset){ public function append(DataObjectSet $doset){
foreach($doset as $item){ foreach($doset as $item){
$this->push($item); $this->push($item);
} }
} }
@ -467,12 +467,12 @@ class DataObjectSet extends ViewableData implements Iterator {
public function getOffset($offset) { public function getOffset($offset) {
$keys = array_keys($this->items); $keys = array_keys($this->items);
foreach($keys as $i => $key) { foreach($keys as $i => $key) {
if($key == key($this->items)) break; if($key == key($this->items)) break;
} }
$requiredKey = $keys[$i + $offset]; $requiredKey = $keys[$i + $offset];
return $this->items [$requiredKey]; return $this->items [$requiredKey];
} }
/** /**
* Gets a specific slice of an existing set. * Gets a specific slice of an existing set.
* *
@ -526,6 +526,9 @@ class DataObjectSet extends ViewableData implements Iterator {
* @return DataObject * @return DataObject
*/ */
public function First() { public function First() {
if(count($this->items) < 1)
return null;
$keys = array_keys($this->items); $keys = array_keys($this->items);
return sizeof($keys) > 0 ? $this->items[$keys[0]] : null; return sizeof($keys) > 0 ? $this->items[$keys[0]] : null;
} }
@ -535,6 +538,9 @@ class DataObjectSet extends ViewableData implements Iterator {
* @return DataObject * @return DataObject
*/ */
public function Last() { public function Last() {
if(count($this->items) < 1)
return null;
$keys = array_keys($this->items); $keys = array_keys($this->items);
return $this->items[$keys[sizeof($keys)-1]]; return $this->items[$keys[sizeof($keys)-1]];
} }
@ -566,7 +572,7 @@ class DataObjectSet extends ViewableData implements Iterator {
$result .= "<li onclick=\"location.href = this.getElementsByTagName('a')[0].href\"><a href=\"$item->Link\">$item->Title</a></li>\n"; $result .= "<li onclick=\"location.href = this.getElementsByTagName('a')[0].href\"><a href=\"$item->Link\">$item->Title</a></li>\n";
} }
$result .= "</ul>\n"; $result .= "</ul>\n";
return $result; return $result;
} }
} }
@ -578,8 +584,8 @@ class DataObjectSet extends ViewableData implements Iterator {
public function forTemplate() { public function forTemplate() {
return $this->UL(); return $this->UL();
} }
/** /**
* Returns the dataset as an array of ID => "FirstName Surname" * Returns the dataset as an array of ID => "FirstName Surname"
* @param string $key Field name to index the array. * @param string $key Field name to index the array.
* @param array $values An array of fieldnames to insert in array * @param array $values An array of fieldnames to insert in array
@ -599,12 +605,12 @@ class DataObjectSet extends ViewableData implements Iterator {
$map[$item->$key] = implode(" ", $mapValues); $map[$item->$key] = implode(" ", $mapValues);
} }
} }
return $map; return $map;
} }
/** /**
* Returns the dataset as an array of ID => Title. * Returns the dataset as an array of ID => Title.
* *
* TODO Duplication from toDropdownMap() * TODO Duplication from toDropdownMap()
* *
* @param string $key The field you wish to use as a key for the array * @param string $key The field you wish to use as a key for the array
@ -613,14 +619,14 @@ class DataObjectSet extends ViewableData implements Iterator {
* @return array * @return array
*/ */
public function map($key = "ID", $value = "Title", $includeBlank=null) { public function map($key = "ID", $value = "Title", $includeBlank=null) {
/* Don't do this, add this locally. /* Don't do this, add this locally.
* Reasons: 1: In some case this blank value don't/mustn't present. * Reasons: 1: In some case this blank value don't/mustn't present.
2: In some case, this balnk value should be customised, such as (Select from below) 2: In some case, this balnk value should be customised, such as (Select from below)
3: In some case, the key need to be explicitly "0", cos "" and "0" need to be treated differently 3: In some case, the key need to be explicitly "0", cos "" and "0" need to be treated differently
*/ */
//$map[''] = "(Select)"; //$map[''] = "(Select)";
/* Instead do this as an option */ /* Instead do this as an option */
if($includeBlank) $map[''] = $includeBlank; if($includeBlank) $map[''] = $includeBlank;
@ -634,7 +640,7 @@ class DataObjectSet extends ViewableData implements Iterator {
$map[$item->$key] = $item->$value; $map[$item->$key] = $item->$value;
} }
} }
return $map; return $map;
} }
/** /**
@ -660,7 +666,7 @@ class DataObjectSet extends ViewableData implements Iterator {
} }
return $list; return $list;
} }
/** /**
* Returns an array of DataObjectSets. The array is keyed by index. * Returns an array of DataObjectSets. The array is keyed by index.
* @param string $index The field name to index the array by. * @param string $index The field name to index the array by.
@ -675,7 +681,7 @@ class DataObjectSet extends ViewableData implements Iterator {
} }
return $result; return $result;
} }
/** /**
* Groups the items by a given field. * Groups the items by a given field.
* Returns a DataObjectSet suitable for use in a nested template. * Returns a DataObjectSet suitable for use in a nested template.
@ -693,13 +699,13 @@ class DataObjectSet extends ViewableData implements Iterator {
} }
return $groupedAsSet; return $groupedAsSet;
} }
/** /**
* Returns a nested unordered list out of a "chain" of DataObject-relations, * Returns a nested unordered list out of a "chain" of DataObject-relations,
* using the automagic ComponentSet-relation-methods to find subsequent DataObjectSets. * using the automagic ComponentSet-relation-methods to find subsequent DataObjectSets.
* The formatting of the list can be different for each level, and is evaluated as an SS-template * The formatting of the list can be different for each level, and is evaluated as an SS-template
* with access to the current DataObjects attributes and methods. * with access to the current DataObjects attributes and methods.
* *
* Example: Groups (Level 0, the "calling" DataObjectSet, needs to be queried externally) * Example: Groups (Level 0, the "calling" DataObjectSet, needs to be queried externally)
* and their Members (Level 1, determined by the Group->Members()-relation). * and their Members (Level 1, determined by the Group->Members()-relation).
* *
@ -713,11 +719,11 @@ class DataObjectSet extends ViewableData implements Iterator {
* Format: * Format:
* array( * array(
* array( * array(
* "dataclass" => "Root", * "dataclass" => "Root",
* "template" => "<li class=\"\$EvenOdd\"><a href=\"admin/crm/show/\$ID\">\$AccountName</a>" * "template" => "<li class=\"\$EvenOdd\"><a href=\"admin/crm/show/\$ID\">\$AccountName</a>"
* ), * ),
* array( * array(
* "dataclass" => "GrantObjects", * "dataclass" => "GrantObjects",
* "template" => "<li class=\"\$EvenOdd\"><a href=\"admin/crm/showgrant/\$ID\">#\$GrantNumber: \$TotalAmount.Nice, \$ApplicationDate.ShortMonth \$ApplicationDate.Year</a>" * "template" => "<li class=\"\$EvenOdd\"><a href=\"admin/crm/showgrant/\$ID\">#\$GrantNumber: \$TotalAmount.Nice, \$ApplicationDate.ShortMonth \$ApplicationDate.Year</a>"
* ) * )
* ); * );
@ -728,7 +734,7 @@ class DataObjectSet extends ViewableData implements Iterator {
public function buildNestedUL($nestingLevels, $ulExtraAttributes = "") { public function buildNestedUL($nestingLevels, $ulExtraAttributes = "") {
return $this->getChildrenAsUL($nestingLevels, 0, "", $ulExtraAttributes); return $this->getChildrenAsUL($nestingLevels, 0, "", $ulExtraAttributes);
} }
/** /**
* Gets called recursively on the child-objects of the chain. * Gets called recursively on the child-objects of the chain.
* *
@ -743,13 +749,13 @@ class DataObjectSet extends ViewableData implements Iterator {
$hasNextLevel = false; $hasNextLevel = false;
$ulExtraAttributes = " $ulExtraAttributes"; $ulExtraAttributes = " $ulExtraAttributes";
$output = "<ul" . eval($ulExtraAttributes) . ">\n"; $output = "<ul" . eval($ulExtraAttributes) . ">\n";
$currentNestingLevel = $nestingLevels[$level]; $currentNestingLevel = $nestingLevels[$level];
// either current or default template // either current or default template
$currentTemplate = (!empty($currentNestingLevel)) ? $currentNestingLevel['template'] : $template; $currentTemplate = (!empty($currentNestingLevel)) ? $currentNestingLevel['template'] : $template;
$myViewer = SSViewer::fromString($currentTemplate); $myViewer = SSViewer::fromString($currentTemplate);
$childrenMethod = $nestingLevels[$level+1]['dataclass']; $childrenMethod = $nestingLevels[$level+1]['dataclass'];
// sql-parts // sql-parts
@ -760,30 +766,30 @@ class DataObjectSet extends ViewableData implements Iterator {
$having = ($nestingLevels[$level+1]['having']) ? $nestingLevels[$level+1]['having'] : null; $having = ($nestingLevels[$level+1]['having']) ? $nestingLevels[$level+1]['having'] : null;
foreach($this as $parent) { foreach($this as $parent) {
$evenOdd = ($itemCount % 2 == 0) ? "even" : "odd"; $evenOdd = ($itemCount % 2 == 0) ? "even" : "odd";
$parent->setField('EvenOdd', $evenOdd); $parent->setField('EvenOdd', $evenOdd);
$template = $myViewer->process($parent); $template = $myViewer->process($parent);
// if no output is selected, fall back to the id to keep the item "clickable" // if no output is selected, fall back to the id to keep the item "clickable"
$output .= $template . "\n"; $output .= $template . "\n";
if($childrenMethod) { if($childrenMethod) {
// workaround for missing groupby/having-parameters in instance_get // workaround for missing groupby/having-parameters in instance_get
// get the dataobjects for the next level // get the dataobjects for the next level
$children = $parent->$childrenMethod($filter, $sort, $join, $limit, $having); $children = $parent->$childrenMethod($filter, $sort, $join, $limit, $having);
if($children) { if($children) {
$output .= $children->getChildrenAsUL($nestingLevels, $level+1, $currentTemplate, $ulExtraAttributes); $output .= $children->getChildrenAsUL($nestingLevels, $level+1, $currentTemplate, $ulExtraAttributes);
} }
} }
$output .= "</li>\n"; $output .= "</li>\n";
$itemCount++; $itemCount++;
} }
$output .= "</ul>\n"; $output .= "</ul>\n";
return $output; return $output;
} }
/** /**
* Returns a new DataObjectSet of the sorted array * Returns a new DataObjectSet of the sorted array
* @param string $fieldname the name of the field on the dataobject that you wish to sort the set by * @param string $fieldname the name of the field on the dataobject that you wish to sort the set by
@ -794,7 +800,7 @@ class DataObjectSet extends ViewableData implements Iterator {
column_sort($this->items, $fieldname, $direction, false); column_sort($this->items, $fieldname, $direction, false);
} }
} }
/** /**
* Remove duplicates from this set based on the dataobjects ID. * Remove duplicates from this set based on the dataobjects ID.
* Assumes all items contained in the set all have IDs. * Assumes all items contained in the set all have IDs.
@ -821,7 +827,7 @@ class DataObjectSet extends ViewableData implements Iterator {
$val .= "</ul>"; $val .= "</ul>";
return $val; return $val;
} }
/** /**
* Groups the set by $groupField and returns the parent of each group whose class * Groups the set by $groupField and returns the parent of each group whose class
* is $groupClassName. If $collapse is true, the group will be collapsed up until an ancestor with the * is $groupClassName. If $collapse is true, the group will be collapsed up until an ancestor with the
@ -839,28 +845,28 @@ class DataObjectSet extends ViewableData implements Iterator {
// indexed by it's parent. The parent IDs are later used to find the parents // indexed by it's parent. The parent IDs are later used to find the parents
// that make up the returned set. // that make up the returned set.
$groupedSet = array(); $groupedSet = array();
// Array to store the subgroups matching the requirements // Array to store the subgroups matching the requirements
$resultsArray = array(); $resultsArray = array();
// Put this item into the array indexed by $groupField. // Put this item into the array indexed by $groupField.
// the keys are later used to retrieve the top-level records // the keys are later used to retrieve the top-level records
foreach( $this->items as $item ) { foreach( $this->items as $item ) {
$groupedSet[$item->$groupField][] = $item; $groupedSet[$item->$groupField][] = $item;
} }
$parentSet = null; $parentSet = null;
// retrieve parents for this set // retrieve parents for this set
// TODO How will we collapse the hierarchy to bridge the gap? // TODO How will we collapse the hierarchy to bridge the gap?
// if collapse is specified, then find the most direct ancestor of type // if collapse is specified, then find the most direct ancestor of type
// $groupClassName // $groupClassName
if($collapse) { if($collapse) {
// The most direct ancestors with the type $groupClassName // The most direct ancestors with the type $groupClassName
$parentSet = array(); $parentSet = array();
// get direct parents // get direct parents
$parents = DataObject::get( 'SiteTree', "`SiteTree`.`$parentField` IN( " . implode( ",", array_keys( $groupedSet ) ) . ")", $sortParents ); $parents = DataObject::get( 'SiteTree', "`SiteTree`.`$parentField` IN( " . implode( ",", array_keys( $groupedSet ) ) . ")", $sortParents );
@ -869,21 +875,21 @@ class DataObjectSet extends ViewableData implements Iterator {
// store the old parent ID. This is required to change the grouped items // store the old parent ID. This is required to change the grouped items
// in the $groupSet array // in the $groupSet array
$oldParentID = $parent->ID; $oldParentID = $parent->ID;
// get the parental stack // get the parental stack
$parentObjects= $parent->parentStack(); $parentObjects= $parent->parentStack();
$parentStack = array(); $parentStack = array();
foreach( $parentObjects as $parentObj ) foreach( $parentObjects as $parentObj )
$parentStack[] = $parentObj->ID; $parentStack[] = $parentObj->ID;
// is some particular IDs are required, then get the intersection // is some particular IDs are required, then get the intersection
if($requiredParents && count($requiredParents)) { if($requiredParents && count($requiredParents)) {
$parentStack = array_intersect($requiredParents, $parentStack); $parentStack = array_intersect($requiredParents, $parentStack);
} }
$newParent = null; $newParent = null;
// If there are no parents, the group can be omitted // If there are no parents, the group can be omitted
if(empty($parentStack)) { if(empty($parentStack)) {
$newParent = new DataObjectSet(); $newParent = new DataObjectSet();
@ -896,13 +902,13 @@ class DataObjectSet extends ViewableData implements Iterator {
foreach( $groupedSet[$oldParentID] as $descendant ) { foreach( $groupedSet[$oldParentID] as $descendant ) {
$groupedSet[$newParent->ID][] = $descendant; $groupedSet[$newParent->ID][] = $descendant;
} }
// Add the most direct ancestor of type $groupClassName // Add the most direct ancestor of type $groupClassName
$parentSet[] = $newParent; $parentSet[] = $newParent;
} }
// otherwise get the parents of these items // otherwise get the parents of these items
} else { } else {
$requiredIDs = array_keys( $groupedSet ); $requiredIDs = array_keys( $groupedSet );
if( $requiredParents && cont($requiredParents)) { if( $requiredParents && cont($requiredParents)) {