[eluser]Phil Sturgeon[/eluser]
How about this.
libraries/REST_controller.php
Code:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class REST_Controller extends Controller {
private $method;
private $format;
private $args;
// List all supported methods, the first will be default
private $supported_formats = array(
'xml' => 'application/xml',
'json' => 'application/json',
'serialize' => 'text/plain',
'php' => 'text/plain'
);
// Constructor function
function __construct()
{
parent::Controller();
$this->args = $this->uri->uri_to_assoc();
$this->format = $this->_detect_format();
$this->method = $this->_detect_method();
}
function _remap($object_called)
{
$controller_method = $object_called.'_'.$this->method;
if($controller_method)
{
$this->$controller_method();
}
}
// Main function to output data
function response($data = '', $http_code = 200)
{
$this->output->set_status_header($http_code);
// If the method exists, call it
if(method_exists($this, '_'.$this->format))
{
// Set a XML header
$this->output->set_header('Content-type: '.$this->supported_formats[$this->format]);
$formatted_data = $this->{'_'.$this->format}($data);
$this->output->set_output( $formatted_data );
}
else
{
$this->output->set_output( $data );
}
}
// Detect which format should be used to output the data
private function _detect_format()
{
if(array_key_exists('format', $this->args) && array_key_exists($this->args['format'], $this->supported_formats))
{
return $this->args['format'];
}
// If a HTTP_ACCEPT header is present...
if($this->input->server('HTTP_ACCEPT'))
{
// Check to see if it matches a supported format
foreach(array_keys($this->supported_formats) as $format)
{
if(strpos($this->input->server('HTTP_ACCEPT'), $format) !== FALSE)
{
return $format;
}
}
}
// If it doesnt match any or no HTTP_ACCEPT header exists, uses the first (default) supported format
list($default)=array_keys($this->supported_formats);
return $default;
}
private function _detect_method()
{
$method = strtolower($this->input->server('REQUEST_METHOD'));
if(in_array($method, array('get', 'delete', 'post', 'put')))
{
return $method;
}
return 'get';
}
// FORMATING FUNCTIONS ---------------------------------------------------------
// Format XML for output
private function _xml($data = array(), $structure = NULL, $basenode = 'xml')
{
// turn off compatibility mode as simple xml throws a wobbly if you don't.
if (ini_get('zend.ze1_compatibility_mode') == 1)
{
ini_set ('zend.ze1_compatibility_mode', 0);
}
if ($structure == NULL)
{
$structure = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><$basenode />");
}
// loop through the data passed in.
foreach($data as $key => $value)
{
// no numeric keys in our xml please!
if (is_numeric($key))
{
// make string key...
//$key = "item_". (string) $key;
$key = "item";
}
// replace anything not alpha numeric
$key = preg_replace('/[^a-z0-9_-]/i', '', $key);
// if there is another array found recrusively call this function
if (is_array($value))
{
$node = $structure->addChild($key);
// recrusive call.
$this->_xml($value, $node, $basenode);
}
else
{
// add single node.
$value = htmlentities($value, ENT_NOQUOTES, "UTF-8");
$UsedKeys[] = $key;
$structure->addChild($key, $value);
}
}
// pass back as string. or simple xml object if you want!
return $structure->asXML();
}
// Encode as JSON
private function _json($data = array())
{
return json_encode($data);
}
// Encode as Serialized array
private function _serialize($data = array())
{
return serialize($data);
}
// Encode raw PHP
private function _php($data = array())
{
return var_export($data);
}
}
?>
Then you can call it in your api controller(s) like so:
controllers/api.php
Code:
<?php
class Api extends REST_Controller {
function something_get()
{
if($user = $this->some_model->get($this->args['id']))
{
$this->response($user, 200); // 200 being the HTTP response code
}
else
{
$this->response(NULL, 404);
}
}
function something_delete()
{
$this->some_model->delete($this->args['id']);
$this->response($user, 200); // 200 being the HTTP response code
}
}
?>
It supports xml, json, serialize and raw php output. The first two will be auto-detected (xml is defaulted if nothing more useful is detected) and latter of the formats require 'format/serialize' to be added to the URI.
This seems to work like a charm, and new formats can be added a piece of piss. This can also be used in a modular environment perfectly!
Feedback?