1
0
Fork 0
forked from lino/radar-wp

Make sure radar depenency is in repo, and upgrade for Price Categories.

This commit is contained in:
ekes 2015-02-24 21:58:33 +01:00
parent c83d681db3
commit 70825293ae
124 changed files with 29219 additions and 19 deletions

View file

@ -0,0 +1,46 @@
<?php
/**
* @file
* Radar entity cache.
*/
namespace Radar\Connect;
use Doctrine\Common\Cache\Cache as CacheInterface;
use Radar\Connect\Entity\Entity;
class Cache {
/**
* @var CacheInteface Doctrine cache.
*/
protected $cache;
public function __construct(CacheInterface $cache) {
$this->cache = $cache;
}
public function contains(Entity $entity) {
return $this->cache->contains($entity->apiUri());
}
public function fetch(Entity $entity) {
return $this->cache->fetch($entity->apiUri());
}
public function save(Entity $entity) {
// TODO Make configurable.
$ttl = array(
'group' => 60 * 60,
'listings_group' => 60 * 60,
'event' => 60 * 5,
'location' => 60 * 60 * 24,
'taxonomy_term' => 60 * 60 * 24 * 30,
);
return $this->cache->save($entity->apiUri(), $entity, $ttl[$entity->type]);
}
public function delete(Entity $entity) {
return $this->cache->delete($entity->apiUri());
}
}

View file

@ -0,0 +1,300 @@
<?php
namespace Radar\Connect;
use Guzzle\Http\ClientInterface;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\Response;
use Radar\Connect\Entity\Entity;
class Connect {
/**
* @var ClientInterface Guzzle HTTP Client
*/
protected $client;
/**
* @var Cache Doctrine cache for entities.
*/
protected $cache;
/**
* @var string URL of API endpoint.
*/
public $apiUrl;
/**
* @var bool Debug switch true for verbose.
*/
public $debug;
/**
* Constructor.
*
* @param ClientInterface $client
* Guzzle HTTP Client.
* @param array $configuration
*/
public function __construct(ClientInterface $client, $configuration = array()) {
$this->client = $client;
$this->client->setDefaultOption('headers', array('Accept' => 'application/json'));
if (!empty($configuration['api_url'])) {
$this->apiUrl = $configuration['api_url'];
}
else {
$this->apiUrl = 'https://new-radar.squat.net/api/1.0/';
}
$this->debug = !empty($configuration['debug']);
}
/**
* For now also just allow direct access to guzzle itself.
*/
public function __call($name, $arguments) {
return call_user_func_array(array($this->client, $name), $arguments);
}
/**
* Set a cache to store entities.
*
* @param \Radar\Connect\Cache $cache
*/
public function setCache(Cache $cache) {
$this->cache = $cache;
}
/**
* Retrieve all fields for single entity.
*
* Entities can be partly loaded. Especially when just a reference on
* an event or group. Use this to retrieve the full entity.
* If there is a cache set, and the entity is still validly cached
* this will be returned rather than making a new query.
*
* @param Entity $entity
* The partly loaded entity.
*
* @return Entity
* The loaded entity.
*/
public function retrieveEntity(Entity $entity) {
if (!empty($this->cache) && $this->cache->contains($entity)) {
return $this->cache->fetch($entity);
}
$request = $this->client->get($entity->apiUri());
$entity = $this->parseResponse($response);
if (!empty($this->cache)) {
$this->cache->save($entity);
}
return $entity;
}
/**
* Retrieve all fields for multiple entities.
*
* As retrieveEntity(), but making multiple concurrent requests.
*
* @param Entity[] $entities
* Array of partly loaded entities.
*
* @return Entity[]
* Array of loaded entities.
*/
public function retrieveEntityMultiple(&$entities) {
$cached = array();
if (!empty($this->cache)) {
foreach($entities as $key => $entity) {
if ($this->cache->contains($entity)) {
$cached[] = $this->cache->fetch($entity);
unset($entities[$key]);
}
}
}
$requests = array();
foreach ($entities as $entity) {
$requests[] = $this->client->get($entity->apiUri());
}
$retrieved = $this->retrieveMultiple($requests);
if (!empty($this->cache)) {
foreach ($retrieved as $entity) {
$this->cache->save($entity);
}
}
$entities = array_merge($cached, $retrieved);
return $entities;
}
/**
* TODO Insert or update an existing Entity.
*/
public function putEntity(Entity $entity) {
}
/**
* Prepare a request to retrieve events.
*
* @see self::retrieve()
*
* @param Filter $filter
* @param array $fields
* A list of fields to load. Optional, default is most available fields.
* @param int $limit
* How many events to return.
*
* @return \Guzzle\Http\Message\Request
* Request object to retrieve.
*/
public function prepareEventsRequest(Filter $filter, $fields = array(), $limit = 500) {
$request = $this->client->get($this->apiUrl . 'search/events.json');
$query = $request->getQuery();
$query->set('facets', $filter->getQuery());
if (! empty($fields)) {
// Always retrieve type.
$fields = array_merge($fields, array('type'));
}
else {
$fields = array(
'title',
'type',
'uuid',
'og_group_ref',
'date_time',
'offline',
'category',
'topic',
'price',
'link',
'phone',
'body',
'image',
'language',
'created',
'updated',
'view_url',
);
}
$query->set('fields', $fields);
$query->set('limit', $limit);
return $request;
}
/**
* Prepare a request to retrieve groups.
*
* @see self::retrieve()
*
* @param Filter $filter
* @param array $fields
* A list of fields to load. Optional, default is most available fields.
* @param int $limit
* How many groups to return.
*
* @return \Guzzle\Http\Message\Request
* Request object to retrieve.
*/
public function prepareGroupsRequest(Filter $filter, $fields = array(), $limit = 500) {
$request = $this->client->get($this->apiUrl . 'search/groups.json');
$query = $request->getQuery();
$query->set('facets', $filter->getQuery());
if (! empty($fields)) {
$fields += array('type');
}
else {
$fields = array(
'title',
'type',
'category',
'offline',
'topic',
'body',
'email',
'weblink',
'offline',
'opening_times',
'phone',
'view_url',
);
}
$query->set('fields', $fields);
$query->set('limit', $limit);
return $request;
}
/**
* Retrieve entities from a prepared request.
*
* @param \Guzzle\Http\Message\RequestInterface $request
*
* @return Entity[]
*/
public function retrieve(RequestInterface $request) {
$response = $this->client->send($request);
if ($this->debug) {
var_export($response->getHeaders());
var_export($response->getBody());
}
return $this->parseResponse($response);
}
/**
* Retrieve entities from multiple prepared requests.
*
* Results are merged into one entity array.
*
* @param \Guzzle\Http\Message\RequestInterface[] $requests
*
* @return Entity[]
*/
public function retrieveMultiple($requests) {
try {
$responses = $this->client->send($requests);
}
catch (MultiTransferException $e) {
foreach ($e->getFailedRequests() as $request) {
}
foreach ($e->getSuccessfulRequests() as $request) {
}
}
$items = array();
foreach ($responses as $response) {
$items = array_merge($items, $this->parseResponse($response));
}
return $items;
}
/**
* Parse a response from the client.
*
* TODO this doesn't need to be in here.
*/
protected function parseResponse(Response $response) {
$items = array();
$content = $response->json();
if (isset($content['type'])) {
$class = __NAMESPACE__ . '\\Entity\\' . Entity::className($content['type']);
$content['apiBase'] = $this->apiUrl;
$items[] = new $class($content);
}
else {
foreach ($content as $key => $item) {
$class = __NAMESPACE__ . '\\Entity\\' . Entity::className($item['type']);
$item['apiBase'] = $this->apiUrl;
$items[] = new $class($item);
}
}
return $items;
}
}

View file

@ -0,0 +1,94 @@
<?php
namespace Radar\Connect\Entity;
abstract class Entity {
public $drupalId;
public $drupalVersionId;
public $uuid;
public $vuuid;
public $type;
protected $apiUri;
protected $apiBase;
/**
* TODO move this to the controller Connect class.
*/
static function className($type) {
$classes = array(
'node' => 'Node',
'group' => 'Group',
'event' => 'Event',
'category' => 'Category',
'listings_group' => 'ListingsGroup',
'location' => 'Location',
'taxonomy_term' => 'TaxonomyTerm',
'category' => 'TaxonomyTerm',
'topic' => 'TaxonomyTerm',
'price' => 'TaxonomyTerm',
);
return $classes[$type];
}
abstract public function __construct($data = array());
/**
* Set data for entity.
*
* @param array $data
*/
public function set($data) {
foreach ($this as $key => $value) {
if (isset($data[$key])) {
$this->$key = $data[$key];
}
}
if (isset($data['uri'])) {
$this->apiUri = $data['uri'];
}
}
/**
* Return the API URI for this entity.
*
* @return string
*/
abstract function apiUri();
/**
* Return the UUID for the entity.
*
* @return string|null
*/
public function getUuid() {
return !empty($this->uuid) ? $this->uuid : null;
}
/**
* Return the Version UUID for the entity.
*
* @return string|null
*/
public function getVuuid() {
return !empty($this->vuuid) ? $this->vuuid : null;
}
/**
* Return the Drupal internal ID for the entity.
*
* @return int|null
*/
public function getInternalId() {
return !empty($this->drupalId) ? $this->drupalId : null;
}
/**
* Return the Drupal internal version ID for the entity.
*
* @return int|null
*/
public function getInternalVid() {
return !empty($this->drupalVersionId) ? $this->drupalVersionId : null;
}
}

View file

@ -0,0 +1,198 @@
<?php
namespace Radar\Connect\Entity;
class Event extends Node {
public $og_group_ref;
public $date_time;
public $image;
public $price_category;
public $price;
public $email;
public $link;
public $offline;
public $phone;
public function __construct($data = array()) {
parent::__construct($data);
$this->type = 'event';
}
public function set($data) {
parent::set($data);
if (isset($data['title_field'])) {
// @todo always title_field?
$this->title = $data['title_field'];
}
}
public function getGroupsRaw() {
return $og_group_ref;
}
/**
* Return associated groups as group entities.
*
* @return Group[]
*/
public function getGroups() {
$groups = array();
foreach ($this->og_group_ref as $group) {
$groups[] = new Group($group);
}
return $groups;
}
/**
* Return raw event date array.
*
* An array of keyed arrays.
*
* Array[]
* ['value'] start unix timestamp
* ['value2'] end unix timestamp
* ['time_start'] start ISO 8601 time with timezone
* ['time_end'] end ISO 8601 time with timezone
* ['rrule'] RFC5545 iCalendar repeat rule
*
* @return array
*/
public function getDatesRaw() {
return $this->date_time;
}
/**
* Return event date.
*
* An array of keyed arrays.
*
* Array[]
* ['start'] \DateTime start
* ['end'] \DateTime|null end
* ['rrule'] RFC 5545 iCalendar repeat rule
*
* @return array
*/
public function getDates() {
$dates = array();
foreach ($this->date_time as $feed_date) {
$this_date = array();
$this_date['start'] = new \DateTime($feed_date['time_start']);
$this_date['end'] = empty($feed_date['time_end']) ? null : new \DateTime($feed_date['time_end']);
$this_date['rrule'] = $feed_date['rrule']; // Null if not set.
$dates[] = $this_date;
}
return $dates;
}
/**
* Return image field data.
*
* TODO API isn't putting the data into the output.
*/
public function getImageRaw() {
return $this->image;
}
public function getPriceCategoryRaw() {
return $this->price_category;
}
/**
* Return price category.
*
* @return TaxonomyTerm[]
*/
public function getPriceCategory() {
$categories = array();
if (is_array($this->price_category)) {
foreach ($this->price_category as $price_category) {
$price_categories[] = new TaxonomyTerm($price_category);
}
}
return $price_categories;
}
/**
* Return the price, free text field.
*
* @return string
* Array of strings describing price.
*/
public function getPrice() {
return $this->price;
}
public function getPriceRaw() {
return $this->price;
}
/**
* Return email.
*
* @return string
*/
public function getEmail() {
return $this->email;
}
public function getEmailRaw() {
return $this->email;
}
/**
* Return array of url links for the event.
*
* @return string[]
*/
public function getLink() {
$links = array();
foreach ($this->link as $link) {
$links[] = $link['url'];
}
return $links;
}
/**
* Return array of array url links for the event.
*
* Keyed with 'url', and unused 'attributes'.
*
* @return array
*/
public function getLinkRaw() {
return $this->link;
}
public function getLocationsRaw() {
return $this->offline;
}
/**
* Return event locations.
*
* @return Location[]
*/
public function getLocations() {
$locations = array();
foreach ($this->offline as $location) {
$locations[] = new Location($location);
}
return $locations;
}
/**
* Return phone number.
*
* @return string
*/
public function getPhone() {
return $this->phone;
}
public function getPhoneRaw() {
return $this->phone;
}
}

View file

@ -0,0 +1,118 @@
<?php
namespace Radar\Connect\Entity;
class Group extends Node {
public $group_logo;
public $image;
public $email;
public $link;
public $offline;
public $opening_times;
public $phone;
function __construct($data = array()) {
parent::__construct($data);
$this->type = 'group';
}
/**
* TODO not appearing in the API output.
*/
public function getGroupLogoRaw() {
return $this->group_logo;
}
/**
* TODO not appearing in the API output.
*/
public function getImageRaw() {
return $this->image->file;
}
/**
* Return email.
*
* @return string
*/
public function getEmail() {
return $this->email;
}
public function getEmailRaw() {
return $this->email;
}
/**
* Return array of url links for the event.
*
* @return string[]
*/
public function getLink() {
$links = array();
foreach ($this->link as $link) {
$links[] = $link['url'];
}
return $links;
}
/**
* Return array of array url links for the event.
*
* Keyed with 'url', and unused 'attributes'.
*
* @return array
*/
public function getLinkRaw() {
return $this->link;
}
/**
* Return group locations.
*
* @return Location[]
*/
public function getLocations() {
$locations = array();
foreach ($this->offline as $location) {
$locations[] = new Location($location);
}
return $locations;
}
public function getLocationsRaw() {
return $this->offline;
}
/**
* Return phone number.
*
* @return string
*/
public function getPhone() {
return $this->phone;
}
public function getPhoneRaw() {
return $this->phone;
}
/**
* Free text description of opening times.
*
* @return string
*/
public function getOpeningTimes() {
return (!empty($this->opening_times['value'])) ? $this->opening_times['value'] : '';
}
/**
* Free text description of opening times.
*
* Keyed array with 'value', and 'format' the Radar internal name of the
* filter format used.
*/
public function getOpeningTimesRaw() {
return $this->opening_times;
}
}

View file

@ -0,0 +1,108 @@
<?php
namespace Radar\Connect\Entity;
class ListingsGroup extends Node {
public $group_logo;
public $email;
public $link;
public $offline;
public $phone;
public $groups_listed;
function __construct($data = array()) {
$this->set($data);
$this->type = 'listings_group';
}
/**
* TODO not appearing in the API output.
*/
public function getGroupLogoRaw() {
return $this->group_logo;
}
/**
* Return email.
*
* @return string
*/
public function getEmail() {
return $this->email;
}
public function getEmailRaw() {
return $this->email;
}
/**
* Return array of url links for the event.
*
* @return string[]
*/
public function getLink() {
$links = array();
foreach ($this->link as $link) {
$links[] = $link['url'];
}
return $links;
}
/**
* Return array of array url links for the event.
*
* Keyed with 'url', and unused 'attributes'.
*
* @return array
*/
public function getLinkRaw() {
return $this->link;
}
/**
* Return group locations.
*
* @return Location[]
*/
public function getLocations() {
$locations = array();
foreach ($this->offline as $location) {
$locations[] = new Location($location);
}
return $locations;
}
public function getLocationsRaw() {
return $this->offline;
}
/**
* Return phone number.
*
* @return string
*/
public function getPhone() {
return $this->phone;
}
public function getPhoneRaw() {
return $this->phone;
}
/**
* Which groups are listed for.
*
* @return Group[]
*/
public function getGroupsListed() {
$groups = array();
foreach ($this->groups_listed as $group) {
$groups[] = new Group($group);
}
return $groups;
}
public function getGroupsListedRaw() {
return $this->groups_listed;
}
}

View file

@ -0,0 +1,114 @@
<?php
namespace Radar\Connect\Entity;
use geoPHP;
class Location extends Entity {
public $title;
public $address;
public $directions;
public $map;
public $timezone;
public function __construct($data = array()) {
$this->set($data);
$this->type = 'location';
}
public function set($data) {
$data = (array) $data;
parent::set($data);
if (isset($data['id'])) {
$this->drupalId = $data['id'];
}
}
public function apiUri() {
if (isset($this->apiUri)) {
return $this->apiUri;
}
elseif (isset($this->uuid)) {
return $this->apiBase . 'location/' . $this->uuid;
}
throw new Exception();
}
public function getTitle() {
return $this->title;
}
/**
* Return address array.
*
* array
* ['country'] two letter code
* ['name_line'] locally known as
* ['first_name']
* ['last_name']
* ['organisation_name']
* ['administrative_area']
* ['sub_administrative_area']
* ['locality'] city name
* ['dependent_locality']
* ['postal_code'] postcode
* ['thoroughfare'] street
* ['premise']
*
* @return array
*/
public function getAddressRaw() {
return $this->address;
}
/**
* Return components of the address, glued with string.
*
* @param array $include
* Key names. See self::getAddressRaw() for list.
* @param string $seperator
* Glue to join components.
*
* @return string
*/
public function getAddress($include = array('name_line', 'thoroughfare', 'locality'), $seperator = ', ') {
$address = array();
foreach ($include as $part) {
if (! empty($this->address[$part])) {
$address[] = $this->address[$part];
}
}
return implode($seperator, $address);
}
public function getDirectionsRaw() {
return $this->directions;
}
/**
* Return the directions text field.
*
* Free text field used for describing how to get to a location.
*
* @return string
*/
public function getDirections() {
return $this->directions;
}
public function getLocationRaw() {
return $this->map;
}
/**
* Return the geographic location.
*
* Usually a point, geocoded or manually added.
*
* @return geoPHP\Geometry
*/
public function getLocation() {
return geoPHP::load($this->map['geom']);
}
}

View file

@ -0,0 +1,166 @@
<?php
namespace Radar\Connect\Entity;
class Node extends Entity {
public $title;
public $body;
public $category;
public $topic;
public $url;
public $edit_url;
public $status;
public $created;
public $changed;
public $language;
public function __construct($data = array()) {
$this->set($data);
}
public function set($data) {
parent::set($data);
if (isset($data['nid'])) {
$this->drupalId = $data['nid'];
}
if (isset($data['vid'])) {
$this->drupalVersionId = $data['vid'];
}
}
public function apiUri() {
if (isset($this->apiUri)) {
return $this->apiUri;
}
elseif (isset($this->uuid)) {
return $this->apiBase . 'node/' . $this->uuid;
}
throw new Exception();
}
public function getTitle() {
return $this->title;
}
/**
* Body or Description of the Entity.
*
* @return string
*/
public function getBody() {
return (!empty($this->body['value'])) ? $this->body['value'] : '';
}
/**
* Body, summary and filter type.
*
* Keyed array with 'value', 'summary' if there is a shorter summary
* and 'format' the Radar internal name of the filter format used.
*
* @return array
*/
public function getBodyRaw() {
return $this->body;
}
public function getCategoriesRaw() {
return $this->category;
}
/**
* Return standard categories.
*
* @return TaxonomyTerm[]
*/
public function getCategories() {
$categories = array();
if (is_array($this->category)) {
foreach ($this->category as $category) {
$categories[] = new TaxonomyTerm($category);
}
}
return $categories;
}
public function getTopicsRaw() {
return $this->topics;
}
/**
* Return free tagging topics
*
* @return TaxonomyTerm[]
*/
public function getTopics() {
$topics = array();
if (is_array($this->topic)) {
foreach ($this->topic as $topic) {
$topics[] = new TaxonomyTerm($topic);
}
}
return $topics;
}
/**
* URL for the event on the site.
*
* @return string
*/
public function getUrlView() {
return $this->url;
}
/**
* URL to edit the event on the site.
*
* @return string
*/
public function getUrlEdit() {
return $this->edit_url;
}
/**
* Published status.
*
* @return bool
* TRUE if published.
*/
public function getStatus() {
return (bool) $this->status;
}
/**
* Created time.
*
* @return \DateTime
*/
public function getCreated() {
$created = new \DateTime();
$created->setTimestamp($this->created);
return $created;
}
/**
* Last updated time.
*
* @return \DateTime
*/
public function getUpdated() {
$updated = new \DateTime();
$updated->setTimestamp($this->changed);
return $updated;
}
/**
* Language code for entity version.
*
* The entity may be available in other languages. This is the language
* code for the present version.
*
* @return string
*/
public function getLanguage() {
return $this->language;
}
}

View file

@ -0,0 +1,54 @@
<?php
namespace Radar\Connect\Entity;
class TaxonomyTerm extends Entity {
public $name;
public $description;
public $node_count;
public $vocabulary;
public function __construct($data = array()) {
$this->set($data);
$this->type = 'taxonomy_term';
}
public function set($data) {
$data = (array) $data;
parent::set($data);
if (isset($data['tid'])) {
$this->drupalId = $data['tid'];
}
if (isset($data['type'])) {
$this->vocabulary = $data['type'];
}
}
public function apiUri() {
if (isset($this->apiUri)) {
return $this->apiUri;
}
elseif (isset($this->uuid)) {
return $this->apiBase . 'taxonomy_term/' . $this->uuid;
}
throw new Exception();
}
public function getTitle() {
return $this->name;
}
/**
* Type of term: 'category' or 'topic'.
*
* @return string
*/
public function getVocabulary() {
return $this->vocabulary;
}
public function getNodeCount() {
return $this->node_count;
}
}

View file

@ -0,0 +1,131 @@
<?php
namespace Radar\Connect;
class Filter {
/**
* @var array
* Query stack.
*/
private $query;
/**
* Filter by group.
*
* @param int $id
* Presently requires the internal node ID, not the uuid.
*/
public function addGroup($id) {
$this->query['group'][] = $id;
}
/**
* Filter by country.
*
* @param string $country
* Country code. Generally ISO, but there are additions.
* @todo Make a query or a list for this.
*/
public function addCountry($country) {
$this->query['country'][] = $country;
}
/**
* Filter by city.
*
* @param string $city
* Name of city.
*/
public function addCity($city) {
$this->query['city'][] = $city;
}
/**
* Filter by year.
*
* @param string $year.
* Optional: year in YYYY format. Default current year.
*/
public function addYear($year = 'now') {
if ($year == 'now') {
$year = date('Y');
}
$this->query['date'][] = $year;
}
/**
* Filter by month.
*
* @param string $month
* Optional: month in MM numeric format. Default current month.
* @param string $year
* Optional: year in YYYY format. Default current year.
*/
public function addMonth($month = 'now', $year = 'now') {
if ($month = 'now') {
$month = date('m');
}
if ($year = 'now') {
$year = date('Y');
}
$this->query['date'][] = $year . '-' . $month;
}
/**
* Filter by day.
*
* @param string day
* Optional: day in DD numeric format. Default curent day.
* @param string $month
* Optional: month in MM numeric format. Default current month.
* @param string $year
* Optional: year in YYYY format. Default current year.
*/
public function addDay($day = 'now', $month = 'now', $year = 'now') {
if ($day = 'now') {
$day = date('d');
}
if ($month = 'now') {
$month = date('m');
}
if ($year = 'now') {
$year = date('Y');
}
$this->query['date'][] = $year . '-' . $month . '-' . $day;
}
/**
* Filter by date.
*
* @param \DateTime date
*/
public function addDate(\DateTime $date) {
$this->query['date'][] = $date->format('Y-m-d');
}
/**
* Filter by category.
*
* @param string category.
* @todo make the list of fixed categories available.
*/
public function addCategory($category) {
$this->query['category'][] = $category;
}
/**
* Filter by price.
*
* @param string $price
* 'free entrance', 'by donation', other strings entered as free text.
*/
public function addPrice($price) {
$this->query['price'][] = $price;
}
/**
* Return the query array.
*/
public function getQuery() {
return $this->query;
}
}