ACC SHELL
<?php
/**
* Copyright 2012-2014 Rackspace US, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace OpenCloud\Common;
use OpenCloud\Common\Log\Logger;
/**
* @deprecated
* @codeCoverageIgnore
*/
class Collection extends Base
{
private $service;
private $itemClass;
private $itemList = array();
private $pointer = 0;
private $sortKey;
private $nextPageClass;
private $nextPageCallback;
private $nextPageUrl;
/**
* A Collection is an array of objects
*
* Some assumptions:
* * The `Collection` class assumes that there exists on its service
* a factory method with the same name of the class. For example, if
* you create a Collection of class `Foobar`, it will attempt to call
* the method `parent::Foobar()` to create instances of that class.
* * It assumes that the factory method can take an array of values, and
* it passes that to the method.
*
* @param Service $service - the service associated with the collection
* @param string $itemclass - the Class of each item in the collection
* (assumed to be the name of the factory method)
* @param array $arr - the input array
*/
public function __construct($service, $class, array $array = array())
{
$service->getLogger()->warning(Logger::deprecated(__METHOD__, 'OpenCloud\Common\Collection\CollectionBuilder'));
$this->setService($service);
$this->setNextPageClass($class);
// If they've supplied a FQCN, only get the last part
$class = (false !== ($classNamePos = strrpos($class, '\\')))
? substr($class, $classNamePos + 1)
: $class;
$this->setItemClass($class);
// Set data
$this->setItemList($array);
}
/**
* Set the entire data array.
*
* @param array $array
*/
private function setItemList(array $array)
{
$this->itemList = $array;
return $this;
}
/**
* Retrieve the entire data array.
*
* @return array
*/
public function getItemList()
{
return $this->itemList;
}
/**
* Set the service.
*
* @param Service|PersistentObject $service
*/
public function setService($service)
{
$this->service = $service;
return $this;
}
/**
* Retrieves the service associated with the Collection
*
* @return Service
*/
public function getService()
{
return $this->service;
}
/**
* Set the resource class name.
*/
private function setItemClass($itemClass)
{
$this->itemClass = $itemClass;
return $this;
}
/**
* Get item class.
*/
private function getItemClass()
{
return $this->itemClass;
}
/**
* Set the key that will be used for sorting.
*/
private function setSortKey($sortKey)
{
$this->sortKey = $sortKey;
return $this;
}
/**
* Get the key that will be used for sorting.
*/
private function getSortKey()
{
return $this->sortKey;
}
/**
* Set next page class.
*/
private function setNextPageClass($nextPageClass)
{
$this->nextPageClass = $nextPageClass;
return $this;
}
/**
* Get next page class.
*/
private function getNextPageClass()
{
return $this->nextPageClass;
}
/**
* for paginated collection, sets the callback function and URL for
* the next page
*
* The callback function should have the signature:
*
* function Whatever($class, $url, $parent)
*
* and the `$url` should be the URL of the next page of results
*
* @param callable $callback the name of the function (or array of
* object, function name)
* @param string $url the URL of the next page of results
* @return void
*/
public function setNextPageCallback($callback, $url)
{
$this->nextPageCallback = $callback;
$this->nextPageUrl = $url;
return $this;
}
/**
* Get next page callback.
*/
private function getNextPageCallback()
{
return $this->nextPageCallback;
}
/**
* Get next page URL.
*/
private function getNextPageUrl()
{
return $this->nextPageUrl;
}
/**
* Returns the number of items in the collection
*
* For most services, this is the total number of items. If the Collection
* is paginated, however, this only returns the count of items in the
* current page of data.
*
* @return int
*/
public function count()
{
return count($this->getItemList());
}
/**
* Pseudonym for count()
*
* @codeCoverageIgnore
*/
public function size()
{
return $this->count();
}
/**
* Resets the pointer to the beginning, but does NOT return the first item
*
* @api
* @return void
*/
public function reset()
{
$this->pointer = 0;
}
/**
* Resets the collection pointer back to the first item in the page
* and returns it
*
* This is useful if you're only interested in the first item in the page.
*
* @api
* @return Base the first item in the set
*/
public function first()
{
$this->reset();
return $this->next();
}
/**
* Return the item at a particular point of the array.
*
* @param mixed $offset
* @return mixed
*/
public function getItem($pointer)
{
return (isset($this->itemList[$pointer])) ? $this->itemList[$pointer] : false;
}
/**
* Add an item to this collection
*
* @param mixed $item
*/
public function addItem($item)
{
$this->itemList[] = $item;
}
/**
* Returns the next item in the page
*
* @api
* @return Base the next item or FALSE if at the end of the page
*/
public function next()
{
if ($this->pointer >= $this->count()) {
return false;
}
$data = $this->getItem($this->pointer++);
$class = $this->getItemClass();
// Are there specific methods in the parent/service that can be used to
// instantiate the resource? Currently supported: getResource(), resource()
foreach (array($class, 'get' . ucfirst($class)) as $method) {
if (method_exists($this->service, $method)) {
return call_user_func(array($this->service, $method), $data);
}
}
// Backup method
if (method_exists($this->service, 'resource')) {
return $this->service->resource($class, $data);
}
return false;
}
/**
* sorts the collection on a specified key
*
* Note: only top-level keys can be used as the sort key. Note that this
* only sorts the data in the current page of the Collection (for
* multi-page data).
*
* @api
* @param string $keyname the name of the field to use as the sort key
* @return void
*/
public function sort($keyname = 'id')
{
$this->setSortKey($keyname);
usort($this->itemList, array($this, 'sortCompare'));
}
/**
* selects only specified items from the Collection
*
* This provides a simple form of filtering on Collections. For each item
* in the collection, it calls the callback function, passing it the item.
* If the callback returns `TRUE`, then the item is retained; if it returns
* `FALSE`, then the item is deleted from the collection.
*
* Note that this should not supersede server-side filtering; the
* `Collection::Select()` method requires that *all* of the data for the
* Collection be retrieved from the server before the filtering is
* performed; this can be very inefficient, especially for large data
* sets. This method is mostly useful on smaller-sized sets.
*
* Example:
* <code>
* $services = $connection->ServiceList();
* $services->Select(function ($item) { return $item->region=='ORD';});
* // now the $services Collection only has items from the ORD region
* </code>
*
* `Select()` is *destructive*; that is, it actually removes entries from
* the collection. For example, if you use `Select()` to find items with
* the ID > 10, then use it again to find items that are <= 10, it will
* return an empty list.
*
* @api
* @param callable $testfunc a callback function that is passed each item
* in turn. Note that `Select()` performs an explicit test for
* `FALSE`, so functions like `strpos()` need to be cast into a
* boolean value (and not just return the integer).
* @returns void
* @throws DomainError if callback doesn't return a boolean value
*/
public function select($testfunc)
{
foreach ($this->getItemList() as $index => $item) {
$test = call_user_func($testfunc, $item);
if (!is_bool($test)) {
throw new Exceptions\DomainError(
Lang::translate('Callback function for Collection::Select() did not return boolean')
);
}
if ($test === false) {
unset($this->itemList[$index]);
}
}
}
/**
* returns the Collection object for the next page of results, or
* FALSE if there are no more pages
*
* Generally, the structure for a multi-page collection will look like
* this:
*
* $coll = $obj->Collection();
* do {
* while ($item = $coll->Next()) {
* // do something with the item
* }
* } while ($coll = $coll->NextPage());
*
* @api
* @return Collection if there are more pages of results, otherwise FALSE
*/
public function nextPage()
{
return ($this->getNextPageUrl() !== null)
? call_user_func($this->getNextPageCallback(), $this->getNextPageClass(), $this->getNextPageUrl())
: false;
}
/**
* Compares two values of sort keys
*/
private function sortCompare($a, $b)
{
$key = $this->getSortKey();
// Handle strings
if (is_string($a->$key)) {
return strcmp($a->$key, $b->$key);
}
// Handle others with logical comparisons
if ($a->$key == $b->$key) {
return 0;
} elseif ($a->$key < $b->$key) {
return -1;
} else {
return 1;
}
}
}
ACC SHELL 2018