Skip to content

Instantly share code, notes, and snippets.

@danbettles
Created June 28, 2012 09:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danbettles/3010245 to your computer and use it in GitHub Desktop.
Save danbettles/3010245 to your computer and use it in GitHub Desktop.
Simple, GET-only version of Rails' ActiveResource for CodeIgniter
<?php
/**
* Active_resource_model is a simple, GET-only version of Rails' ActiveResource
* (http://api.rubyonrails.org/classes/ActiveResource/Base.html) for CodeIgniter.
*
* Only JSON data sources are supported at present. Active_resource_model requires the CodeIgniter "curl" library
* (http://getsparks.org/packages/curl/show).
*
* Copy this file into application/models and then add "Active_resource_model" to the models array in
* application/config/autoload.php.
*
* Simply create model classes that extend "Active_resource_model". You must set the base URL of the data source
* (the "site" instance variable) in each subclass. Use Active_resource_model::find_by_id() and/or
* Active_resource_model::find_all() to fetch records. Get attributes from instances using "get_<attribute name>".
*
* @author Dan Bettles <dan@danbettles.net>
* @copyright 2012 Dan Bettles
* @license http://www.opensource.org/licenses/MIT MIT
*/
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* Active_resource_model
*
* @author Dan Bettles <dan@danbettles.net>
*/
class Active_resource_model extends CI_Model {
/**
* The URL of the API.
*
* @var string
*/
public $site;
/**
* The name of the format of the data that will be requested from the API.
*
* @var string
*/
public $format = 'json';
/**
* The model's attributes.
*
* @var array
*/
private $_attributes = array();
/**
* The name of this model in the API.
*
* @var string
*/
public $element_name;
/**
* __construct()
*
* @see parent::__construct
*/
public function __construct()
{
parent::__construct();
$this->load->spark('curl/1.2.1');
$this->load->helper('inflector');
}
/**
* Returns the object with the specified ID, or throws an exception if the object doesn't exist
*
* @param mixed $object_id
*
* @return Active_resource
* @throws InvalidArgumentException If the ID is invalid
* @throws RuntimeException If the object does not exist
*/
public function find_by_id($object_id)
{
$this->_ensure_id_valid($object_id);
$api_request_url = $this->_get_api_controller_url() . '/' . $object_id . '.' . $this->_get_format();
$something = $this->_fetch_json($api_request_url);
if ($something === FALSE) {
//@todo Create a more appropriate, custom exception
throw new RuntimeException('The object does not exist');
}
return $something;
}
/**
* Returns TRUE if the specified ID is valid, or throws an exception otherwise
*
* @param mixed $object_id
*
* @return bool
* @throws InvalidArgumentException If the ID is invalid
*/
private function _ensure_id_valid($object_id)
{
if ( ! (is_scalar($object_id) AND strlen((string) $object_id)))
{
throw new InvalidArgumentException('The ID is invalid');
}
return TRUE;
}
/**
* Returns the name of the API controller corresponding to this model
*
* @return string
*/
private function _get_api_controller_name()
{
$element_name = $this->_get_element_name();
if (is_string($element_name) AND strlen($element_name)) {
return plural($element_name);
}
return strtolower(plural(preg_replace('/_model$/i', '', get_class($this))));
}
/**
* Returns the URL of the API, or throws an exception if the URL hasn't been set
*
* @return string
* @throws RuntimeException The URL of the API has not been set
*/
private function _get_site()
{
if ( ! strlen($this->site))
{
throw new RuntimeException('The URL of the API has not been set');
}
return rtrim($this->site, '/');
}
/**
* Returns the name of the format of the data that will be requested from the API
*
* @return string
*/
private function _get_format()
{
return ltrim($this->format, '.');
}
/**
* Creates an instance of this class using values in the specified object
*
* @param stdClass $plain_object
*
* @return Active_resource_model
*/
private function _create_instance_from_attrs(stdClass $plain_object)
{
$instance = new $this();
foreach ((array) $plain_object as $attribute_name => $attribute_value) {
$instance->{"set_{$attribute_name}"}($attribute_value);
}
return $instance;
}
/**
* Provides setters and getters for attributes
*
* @param string $method_name Name of the method
* @param array $arguments Arguments passed to the method
*
* @return mixed
* @throws RuntimeException If the method does not exist
*/
public function __call($method_name, array $arguments)
{
$method_supported = (bool) preg_match('/^(set|get)_(.+)/', $method_name, $matches);
if ( ! $method_supported) {
throw new RuntimeException('The method does not exist');
}
switch ($matches[1]) {
case 'set':
$this->_attributes[$matches[2]] = reset($arguments);
break;
case 'get':
return $this->_attributes[$matches[2]];
break;
}
}
/**
* Returns the URL of the API controller corresponding to this model
*
* @return string
*/
private function _get_api_controller_url()
{
return $this->_get_site() . '/' . $this->_get_api_controller_name();
}
/**
* Returns all objects
*
* @param array [$arguments = array()]
*
* @return array
*/
public function find_all(array $arguments = array())
{
$api_request_url = $this->_get_api_controller_url() . '.' . $this->_get_format();
$api_request_url .= $this->_create_api_req_url_query($arguments);
$something = $this->_fetch_json($api_request_url);
return $something === FALSE ? array() : $something;
}
/**
* Returns either a single object or an array of objects, or FALSE if the API returned nothing
*
* @param string $api_request_url URL
*
* @return mixed
*/
private function _fetch_json($api_request_url)
{
$json = $this->curl->simple_get($api_request_url);
if ($json === FALSE) {
return FALSE;
}
$something = json_decode($json);
if (is_array($something)) {
$objects = array();
foreach ($something as $plain_object) {
$objects[] = $this->_create_instance_from_attrs($plain_object);
}
return $objects;
}
return $this->_create_instance_from_attrs($something);
}
/**
* Creates a query-string for an API request URL from the specified arguments
*
* @param array $arguments
*
* @return string
*/
private function _create_api_req_url_query(array $arguments)
{
return empty($arguments) ? '' : '?' . http_build_query($arguments);
}
/**
* Returns the element name
*
* @return string
*/
private function _get_element_name()
{
return $this->element_name;
}
}
//Location: ./models/active_resource_model.php
//End of file active_resource_model.php
<?php
/**
* Release_model
*
* @author Dan Bettles <dan@danbettles.net>
* @copyright 2012 Dan Bettles
* @license http://www.opensource.org/licenses/MIT MIT
*/
/**
* Release_model
*
* @author Dan Bettles <dan@danbettles.net>
*/
class Release_model extends Active_resource_model {
/**
* Tracks.
*
* @var array
*/
private $_release_tracks = array();
/**
* __construct
*/
public function __construct()
{
parent::__construct();
$archaic_horizon_api_cfg = $this->config->item('archaic_horizon_api', 'app');
$this->site = $archaic_horizon_api_cfg['site'];
}
/**
* Scope
*
* Returns all releases in reverse chronological order
*
* @return array
*/
public function history()
{
return $this->find_all(array('order' => 'released_at', 'in_reverse' => 1));
}
/**
* Scope
*
* Returns the summary of the latest release or throws an exception otherwise
*
* @return Release_model
* @throws RuntimeException If there is no latest release
*/
public function latest_summary()
{
$something = $this->find_all(array(
'order' => 'released_at',
'in_reverse' => 1,
'num_per_page' => 1,
'page' => 1
));
if (empty($something)) {
throw new RuntimeException('There is no latest release');
}
return reset($something);
}
/**
* Returns the description in HTML format
*
* @return string
*/
public function get_description_html()
{
$this->load->spark('markdown/1.2.0');
return parse_markdown($this->get_description());
}
/**
* Fetches the specified release and then fetches its associated objects
*
* @see parent::find_by_id()
*/
public function find_by_id($object_id)
{
$release = parent::find_by_id($object_id);
$release->_fetch_release_tracks();
return $release;
}
/**
* _fetch_release_tracks
*
* @return void
*/
private function _fetch_release_tracks()
{
$this->load->model('Release_track_model');
$this->_release_tracks = $this->Release_track_model->find_all(array(
'release_code' => $this->get_code(),
'order' => 'position'
));
}
/**
* get_release_tracks
*
* @return array
*/
public function get_release_tracks()
{
return $this->_release_tracks;
}
}
//Location: ./models/release_model.php
//End of file release_model.php
<?php
/**
* Release_track_model
*
* @author Dan Bettles <dan@danbettles.net>
* @copyright 2012 Dan Bettles
*/
/**
* Release_track_model
*
* @author Dan Bettles <dan@danbettles.net>
*/
class Release_track_model extends Active_resource_model {
/**
* __construct
*/
public function __construct()
{
parent::__construct();
$archaic_horizon_api_cfg = $this->config->item('archaic_horizon_api', 'app');
$this->site = $archaic_horizon_api_cfg['site'];
$this->element_name = 'track';
}
/**
* Returns the length of the track in an ISO 8601 duration
*
* @return string
*/
public function get_iso_8601_duration()
{
list($minutes, $seconds) = explode(':', $this->get_time(), 2);
return "PT{$minutes}M{$seconds}S";
}
}
//Location: ./models/release_track_model.php
//End of file release_track_model.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment