<?php
class AWeberCollection extends AWeberResponse implements ArrayAccess, Iterator, Countable {
protected $pageSize = 100;
protected $_entries = array();
/**
* @var array Holds list of keys that are not publicly accessible
*/
protected $_privateData = array(
'entries',
'start',
'next_collection_link',
);
/**
* getById
*
* Gets an entry object of this collection type with the given id
* @param mixed $id ID of the entry you are requesting
* @access public
* @return AWeberEntry
*/
public function getById($id) {
$data = $this->adapter->request('GET', "{$this->url}/{$id}");
return $this->_makeEntry($data, $id, "{$this->url}/{$id}");
}
/**
* create
*
* Invoke the API method to CREATE a new entry resource.
*
* Note: Not all entry resources are eligible to be created, please
* refer to the AWeber API Reference Documentation at
* https://labs.aweber.com/docs/reference/1.0 for more
* details on which entry resources may be created and what
* attributes are required for creating resources.
*
* @access public
* @param params mixed associtative array of key/value pairs.
* @return AWeberEntry(Resource) The new resource created
*/
public function create($kv_pairs) {
# Create Resource
$params = array_merge(array('ws.op' => 'create'), $kv_pairs);
$data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers'));
$this->_entries = array();
# Return new Resource
$url = $data['Location'];
$resource_data = $this->adapter->request('GET', $url);
return new AWeberEntry($resource_data, $url, $this->adapter);
}
/**
* find
*
* Invoke the API 'find' operation on a collection to return a subset
* of that collection. Not all collections support the 'find' operation.
* refer to https://labs.aweber.com/docs/reference/1.0 for more information.
*
* @param mixed $search_data Associative array of key/value pairs used as search filters
* * refer to https://labs.aweber.com/docs/reference/1.0 for a
* complete list of valid search filters.
* * filtering on attributes that require additional permissions to
* display requires an app authorized with those additional permissions.
* @access public
* @return AWeberCollection
*/
public function find($search_data) {
# invoke find operation
$params = array_merge($search_data, array('ws.op' => 'find'));
$data = $this->adapter->request('GET', $this->url, $params);
# get total size
$ts_params = array_merge($params, array('ws.show' => 'total_size'));
$total_size = $this->adapter->request('GET', $this->url, $ts_params, array('return' => 'integer'));
$data['total_size'] = $total_size;
# return collection
return $this->readResponse($data, $this->url);
}
/** getParentEntry
*
* Gets an entry's parent entry
* Returns NULL if no parent entry
*/
public function getParentEntry(){
$url_parts = explode('/', $this->url);
$size = count($url_parts);
#Remove collection id and slash from end of url
$url = substr($this->url, 0, -strlen($url_parts[$size-1])-1);
try {
$data = $this->adapter->request('GET', $url);
return new AWeberEntry($data, $url, $this->adapter);
} catch (Exception $e) {
return NULL;
}
}
/**
* _getPageParams
*
* Returns an array of GET params used to set the page of a collection
* request
* @param int $start Which entry offset should this page start on?
* @param int $size How many entries should be included in this page?
* @access protected
* @return void
*/
protected function _getPageParams($start=0, $size=20) {
if ($start > 0) {
$params = array(
'ws.start' => $start,
'ws.size' => $size,
);
ksort($params);
} else {
$params = array();
}
return $params;
}
/**
* _type
*
* Interpret what type of resources are held in this collection by
* analyzing the URL
*
* @access protected
* @return void
*/
protected function _type() {
$urlParts = explode('/', $this->url);
$type = array_pop($urlParts);
return $type;
}
/**
* _calculatePageSize
*
* Calculates the page size of this collection based on the data in the
* next and prev links.
*
* @access protected
* @return integer
*/
protected function _calculatePageSize() {
if (array_key_exists('next_collection_link', $this->data)) {
$url = $this->data['next_collection_link'];
$urlParts = parse_url($url);
if (empty($urlParts['query'])) return $this->pageSize;
$query = array();
parse_str($urlParts['query'], $query);
if (empty($query['ws_size'])) return $this->pageSize;
$this->pageSize = $query['ws_size'];
}
return $this->pageSize;
}
/**
* _loadPageForOffset
*
* Makes a request for an additional page of entries, based on the given
* offset. Calculates the start / size of the page needed to get that
* offset, requests for it, and then merges the data into it internal
* collection of entry data.
*
* @param mixed $offset The offset requested, 0 to total_size-1
* @access protected
* @return void
*/
protected function _loadPageForOffset($offset) {
$this->_calculatePageSize();
$start = round($offset / $this->pageSize) * $this->pageSize;
$params = $this->_getPageParams($start, $this->pageSize);
// Loading page
$data = $this->adapter->request('GET', $this->url, $params);
$this->adapter->debug = false;
$rekeyed = array();
foreach ($data['entries'] as $key => $entry) {
$rekeyed[$key+$data['start']] = $entry;
}
$this->data['entries'] = array_merge($this->data['entries'], $rekeyed);
}
/**
* _getEntry
*
* Makes sure that entry offset's page is loaded, then returns it. Returns
* null if the entry can't be loaded, even after requesting the needed
* page.
*
* @param mixed $offset Offset being requested.
* @access protected
* @return void
*/
protected function _getEntry($offset) {
if (empty($this->data['entries'][$offset])) {
$this->_loadPageForOffset($offset);
}
return (empty($this->data['entries'][$offset]))? null :
$this->data['entries'][$offset];
}
/**
* _makeEntry
*
* Creates an entry object from the given entry data. Optionally can take
* the id AND URL of the entry, though that data can be infered from the
* context in which _makeEntry is being called.
*
* @param mixed $data Array of data returned from an API request for
* entry, or as part of the entries array in this collection.
* @param mixed $id ID of the entry. (Optional)
* @param mixed $url URL used to retrieve this entry (Optional)
* @access protected
* @return void
*/
protected function _makeEntry($data, $id = false, $url = false) {
if ((!$url) or (!$id)) {
// if either the url or id is omitted, grab the url from the
// self_link of the resource
$url = $this->adapter->app->removeBaseUri($data['self_link']);
} else {
$url = "{$this->url}/{$id}";
}
return new AWeberEntry($data, $url, $this->adapter);
}
/**
* ArrayAccess interface methods
*
* Allows this object to be accessed via bracket notation (ie $obj[$x])
* http://php.net/manual/en/class.arrayaccess.php
*/
public function offsetSet($offset, $value) { }
public function offsetUnset($offset) {}
public function offsetExists($offset) {
if ($offset >=0 && $offset < $this->total_size) {
return true;
}
return false;
}
public function offsetGet($offset) {
if (!$this->offsetExists($offset)) return null;
if (!empty($this->_entries[$offset])) return $this->_entries[$offset];
$this->_entries[$offset] = $this->_makeEntry($this->_getEntry($offset));
return $this->_entries[$offset];
}
/**
* Iterator interface methods
*
* Provides iterator functionality.
* http://php.net/manual/en/class.iterator.php
*/
protected $_iterationKey = 0;
public function current() {
return $this->offsetGet($this->_iterationKey);
}
public function key() {
return $this->_iterationKey;
}
public function next() {
$this->_iterationKey++;
}
public function rewind() {
$this->_iterationKey = 0;
}
public function valid() {
return $this->offsetExists($this->key());
}
/**
* Countable interface methods
*
* Allows PHP's count() and sizeOf() functions to act on this object
* http://www.php.net/manual/en/class.countable.php
*/
public function count() {
return $this->total_size;
}
}