1) ? func_get_args() : $items;
// We now have support for using the key of a data object set
foreach($itemsArr as $i => $item) {
if(is_subclass_of($item, 'ViewableData')) {
$this->items[$i] = $item;
} elseif(is_object($item) || ArrayLib::is_associative($item)) {
$this->items[$i] = new ArrayData($item);
} else {
user_error(
"DataObjectSet::__construct: Passed item #{$i} is not an object or associative array,
can't be properly iterated on in templates",
E_USER_WARNING
);
$this->items[$i] = $item;
}
}
}
parent::__construct();
}
/**
* Necessary for interface ArrayAccess. Returns whether an item with $key exists
* @param mixed $key
* @return bool
*/
public function offsetExists($key) {
return isset($this->items[$key]);
}
/**
* Necessary for interface ArrayAccess. Returns item stored in array with index $key
* @param mixed $key
* @return DataObject
*/
public function offsetGet($key) {
return $this->items[$key];
}
/**
* Necessary for interface ArrayAccess. Set an item with the key in $key
* @param mixed $key
* @param mixed $value
*/
public function offsetSet($key, $value) {
$this->items[$key] = $value;
}
/**
* Necessary for interface ArrayAccess. Unset an item with the key in $key
* @param mixed $key
*/
public function offsetUnset($key) {
unset($this->items[$key]);
}
/**
* Destory all of the DataObjects in this set.
*/
public function destroy() {
foreach($this as $item) {
$item->destroy();
}
}
/**
* Removes all the items in this set.
*/
public function emptyItems() {
$this->items = array();
}
/**
* Convert this DataObjectSet to an array of DataObjects.
* @param string $index Index the array by this field.
* @return array
*/
public function toArray($index = null) {
$map = array();
foreach($this as $item) {
if($index) $map[$item->$index] = $item;
else $map[] = $item;
}
return $map;
}
/**
* Convert this DataObjectSet to an array of maps.
* @param string $index Index the array by this field.
* @return array
*/
public function toNestedArray($index = null){
if(!$index) {
$index = "ID";
}
$map = array();
foreach( $this as $item ) {
$map[$item->$index] = $item->getAllFields();
}
return $map;
}
/**
* Returns an array of ID => Title for the items in this set.
*
* This is an alias of {@link DataObjectSet->map()}
*
* @deprecated 2.5 Please use map() instead
*
* @param string $index The field to use as a key for the array
* @param string $titleField The field (or method) to get values for the map
* @param string $emptyString Empty option text e.g "(Select one)"
* @param bool $sort Sort the map alphabetically based on the $titleField value
* @return array
*/
public function toDropDownMap($index = 'ID', $titleField = 'Title', $emptyString = null, $sort = false) {
return $this->map($index, $titleField, $emptyString, $sort);
}
/**
* Set number of objects on each page.
* @param int $length Number of objects per page
*/
public function setPageLength($length) {
$this->pageLength = $length;
}
/**
* Set the page limits.
* @param int $pageStart The start of this page.
* @param int $pageLength Number of objects per page
* @param int $totalSize Total number of objects.
*/
public function setPageLimits($pageStart, $pageLength, $totalSize) {
$this->pageStart = $pageStart;
$this->pageLength = $pageLength;
$this->totalSize = $totalSize;
}
/**
* Get the page limits
* @return array
*/
public function getPageLimits() {
return array(
'pageStart' => $this->pageStart,
'pageLength' => $this->pageLength,
'totalSize' => $this->totalSize,
);
}
/**
* 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
*/
public function parseQueryLimit(SQLQuery $query) {
if($query->limit) {
if(is_array($query->limit)) {
$length = $query->limit['limit'];
$start = $query->limit['start'];
} else if(stripos($query->limit, 'OFFSET')) {
list($length, $start) = preg_split("/ +OFFSET +/i", trim($query->limit));
} else {
$result = preg_split("/ *, */", trim($query->limit));
$start = $result[0];
$length = isset($result[1]) ? $result[1] : null;
}
if(!$length) {
$length = $start;
$start = 0;
}
$this->setPageLimits($start, $length, $query->unlimitedRowCount());
}
}
/**
* Returns the number of the current page.
* @return int
*/
public function CurrentPage() {
return floor($this->pageStart / $this->pageLength) + 1;
}
/**
* Returns the total number of pages.
* @return int
*/
public function TotalPages() {
if($this->totalSize == 0) {
$this->totalSize = $this->Count();
}
if($this->pageLength == 0) {
$this->pageLength = 10;
}
return ceil($this->totalSize / $this->pageLength);
}
/**
* 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
* show the pages surrounding the current page, so you can still get to the deeper pages.
* @param int $maxPages The maximum number of pages to return
* @return DataObjectSet
*/
public function Pages($maxPages = 0){
$ret = new DataObjectSet();
if($maxPages) {
$startPage = ($this->CurrentPage() - floor($maxPages / 2)) - 1;
$endPage = $this->CurrentPage() + floor($maxPages / 2);
if($startPage < 0) {
$startPage = 0;
$endPage = $maxPages;
}
if($endPage > $this->TotalPages()) {
$endPage = $this->TotalPages();
$startPage = max(0, $endPage - $maxPages);
}
} else {
$startPage = 0;
$endPage = $this->TotalPages();
}
for($i=$startPage; $i < $endPage; $i++){
$link = HTTP::setGetVar($this->paginationGetVar, $i*$this->pageLength);
$thePage = new ArrayData(array(
"PageNum" => $i+1,
"Link" => $link,
"CurrentBool" => ($this->CurrentPage() == $i+1)?true:false,
)
);
$ret->push($thePage);
}
return $ret;
}
/*
* Display a summarized pagination which limits the number of pages shown
* "around" the currently active page for visual balance.
* In case more paginated pages have to be displayed, only
*
* Example: 25 pages total, currently on page 6, context of 4 pages
* [prev] [1] ... [4] [5] [[6]] [7] [8] ... [25] [next]
*
* Example template usage:
*
* <% if MyPages.MoreThanOnePage %>
* <% if MyPages.NotFirstPage %>
* Prev
* <% end_if %>
* <% control MyPages.PaginationSummary(4) %>
* <% if CurrentBool %>
* $PageNum
* <% else %>
* <% if Link %>
* $PageNum
* <% else %>
* ...
* <% end_if %>
* <% end_if %>
* <% end_control %>
* <% if MyPages.NotLastPage %>
* Next
* <% end_if %>
* <% end_if %>
*
*
* @param integer $context Number of pages to display "around" the current page. Number should be even,
* because its halved to either side of the current page.
* @return DataObjectSet
*/
public function PaginationSummary($context = 4) {
$ret = new DataObjectSet();
// convert number of pages to even number for offset calculation
if($context % 2) $context--;
// find out the offset
$current = $this->CurrentPage();
$totalPages = $this->TotalPages();
// if the first or last page is shown, use all content on one side (either left or right of current page)
// otherwise half the number for usage "around" the current page
$offset = ($current == 1 || $current == $totalPages) ? $context : floor($context/2);
$leftOffset = $current - ($offset);
if($leftOffset < 1) $leftOffset = 1;
if($leftOffset + $context > $totalPages) $leftOffset = $totalPages - $context;
for($i=0; $i < $totalPages; $i++) {
$link = HTTP::setGetVar($this->paginationGetVar, $i*$this->pageLength);
$num = $i+1;
$currentBool = ($current == $i+1) ? true:false;
if(
($num == $leftOffset-1 && $num != 1 && $num != $totalPages)
|| ($num == $leftOffset+$context+1 && $num != 1 && $num != $totalPages)
) {
$ret->push(new ArrayData(array(
"PageNum" => null,
"Link" => null,
"CurrentBool" => $currentBool,
)
));
} else if($num == 1 || $num == $totalPages || in_array($num, range($current-$offset,$current+$offset))) {
$ret->push(new ArrayData(array(
"PageNum" => $num,
"Link" => $link,
"CurrentBool" => $currentBool,
)
));
}
}
return $ret;
}
/**
* Returns true if the current page is not the first page.
* @return boolean
*/
public function NotFirstPage(){
return $this->CurrentPage() != 1;
}
/**
* Returns true if the current page is not the last page.
* @return boolean
*/
public function NotLastPage(){
return $this->CurrentPage() != $this->TotalPages();
}
/**
* Returns true if there is more than one page.
* @return boolean
*/
public function MoreThanOnePage(){
return $this->TotalPages() > 1;
}
function FirstItem() {
return isset($this->pageStart) ? $this->pageStart + 1 : 1;
}
function LastItem() {
if(isset($this->pageStart)) {
return min($this->pageStart + $this->pageLength, $this->totalSize);
} else {
return min($this->pageLength, $this->totalSize);
}
}
/**
* Returns the URL of the previous page.
* @return string
*/
public function PrevLink() {
if($this->pageStart - $this->pageLength >= 0) {
return HTTP::setGetVar($this->paginationGetVar, $this->pageStart - $this->pageLength);
}
}
/**
* Returns the URL of the next page.
* @return string
*/
public function NextLink() {
if($this->pageStart + $this->pageLength < $this->totalSize) {
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)
*
* @param string $var The variable to go in the GET string (Defaults to 'start')
*/
public function setPaginationGetVar($var) {
$this->paginationGetVar = $var;
}
/**
* Add an item to the DataObject Set.
* @param DataObject $item Item to add.
* @param string $key Key to index this DataObject by.
*/
public function push($item, $key = null) {
if($key != null) {
unset($this->items[$key]);
$this->items[$key] = $item;
} else {
$this->items[] = $item;
}
}
/**
* Add an item to the beginning of the DataObjectSet
* @param DataObject $item Item to add
* @param string $key Key to index this DataObject by.
*/
public function insertFirst($item, $key = null) {
if($key == null) {
array_unshift($this->items, $item);
} else {
$this->items = array_merge(array($key=>$item), $this->items);
}
}
/**
* Insert a DataObject at the beginning of this set.
* @param DataObject $item Item to insert.
*/
public function unshift($item) {
$this->insertFirst($item);
}
/**
* Remove a DataObject from the beginning of this set and return it.
* This is the equivalent of pop() but acts on the head of the set.
* Opposite of unshift().
*
* @return DataObject (or null if there are no items in the set)
*/
public function shift() {
return array_shift($this->items);
}
/**
* Remove a DataObject from the end of this set and return it.
* This is the equivalent of shift() but acts on the tail of the set.
* Opposite of push().
*
* @return DataObject (or null if there are no items in the set)
*/
public function pop() {
return array_pop($this->items);
}
/**
* Remove a DataObject from this set.
* @param DataObject $itemObject Item to remove.
*/
public function remove($itemObject) {
foreach($this->items as $key=>$item){
if($item === $itemObject){
unset($this->items[$key]);
}
}
}
/**
* Replaces $itemOld with $itemNew
*
* @param DataObject $itemOld
* @param DataObject $itemNew
*/
public function replace($itemOld, $itemNew) {
foreach($this->items as $key => $item) {
if($item === $itemOld) {
$this->items[$key] = $itemNew;
return;
}
}
}
/**
* Merge another set onto the end of this set.
* To merge without causing duplicates, consider calling
* {@link removeDuplicates()} after this method on the new set.
*
* @param DataObjectSet $anotherSet Set to mege onto this set.
*/
public function merge($anotherSet){
if($anotherSet) {
foreach($anotherSet as $item){
$this->push($item);
}
}
}
/**
* Gets a specific slice of an existing set.
*
* @param int $offset
* @param int $length
* @return DataObjectSet
*/
public function getRange($offset, $length) {
$set = array_slice($this->items, (int)$offset, (int)$length);
return new DataObjectSet($set);
}
/**
* Returns an Iterator for this DataObjectSet.
* This function allows you to use DataObjectSets in foreach loops
* @return DataObjectSet_Iterator
*/
public function getIterator() {
return new DataObjectSet_Iterator($this->items);
}
/**
* Returns false if the set is empty.
* @return boolean
*/
public function exists() {
return $this->count() > 0;
}
/**
* Return the first item in the set.
* @return DataObject
*/
public function First() {
if(count($this->items) < 1)
return null;
$keys = array_keys($this->items);
return $this->items[$keys[0]];
}
/**
* Return the last item in the set.
* @return DataObject
*/
public function Last() {
if(count($this->items) < 1)
return null;
$keys = array_keys($this->items);
return $this->items[$keys[sizeof($keys)-1]];
}
/**
* Return the total number of items in this dataset.
* @return int
*/
public function TotalItems() {
return $this->totalSize ? $this->totalSize : $this->Count();
}
/**
* Returns the actual number of items in this dataset.
* @return int
*/
public function Count() {
return sizeof($this->items);
}
/**
* Returns this set as a XHTML unordered list.
* @return string
*/
public function UL() {
if($this->exists()) {
$result = "