Skip to content

Instantly share code, notes, and snippets.

@jaredhoyt
Created July 8, 2010 16:47
Show Gist options
  • Save jaredhoyt/468292 to your computer and use it in GitHub Desktop.
Save jaredhoyt/468292 to your computer and use it in GitHub Desktop.
<?php
class RestComponent extends Object {
/**
* Determines whether or not to use pre-built views.
*
* @var boolean
* @access public
*/
var $autoRender = true;
/**
* HTTP response header codes.
*
* @var array
* @access public
*/
var $codes = array(
200 => 'OK',
403 => 'Forbidden'
);
/**
* View variables to be extracted and compiled for api response.
*
* @var array
* @access public
*/
var $responseVars = array();
/**
* Supported response formats.
*
* @var array
* @access public
*/
var $responseTypes = array('xml', 'json', 'php');
/**
* Field name on user's table used to authentication api token.
*
* @var string
* @access public
*/
var $tokenField = '';
/**
* Additional query conditions to use when looking up and authenticating users,
* i.e. array('User.api_access' => 1).
*
* Note: Conditions in AuthComponent::userScope do not have to be duplicated here.
*
* @var array
* @access public
*/
var $userScope = array();
/**
* Holds information for request logging.
*
* @var array
* @access protected
*/
var $_status = array(
'httpcode' => 200,
'response' => '',
'user_id' => 0
);
/**
* Initialize component and merge settings.
*
* @param object $controller Instantiating controller
* @param array $settings Component settings
* @return void
* @access public
*/
function initialize(&$controller, $settings = array()) {
$this->params = $controller->params;
$this->_set($settings);
if ($this->isRest()) {
if ($this->autoRender) {
$controller->view = 'Rest.' . Inflector::camelize($this->params['url']['ext']);
}
$this->RestLog = ClassRegistry::init('RestLog');
$this->RestLog->create(array(
'controller' => $this->params['controller'],
'action' => $this->params['action'],
'ip' => $_SERVER['REMOTE_ADDR'],
'params' => serialize($this->params)
));
$this->RestLog->save();
if (isset($controller->Auth)) {
$this->Auth =& $controller->Auth;
$action = strtolower($controller->params['action']);
$allowedActions = array_map('strtolower', $this->Auth->allowedActions);
if ($this->Auth->allowedActions != array('*') && !in_array($action, $allowedActions)) {
if (isset($controller->Security)) {
$this->Security =& $controller->Security;
}
if (!$this->isAuthorized($controller)) {
$this->_status['httpcode'] = 403;
$controller->RequestHandler->startup($controller);
$controller->render();
exit();
}
}
}
}
}
/**
* Extracts view variables and compiles them into a single response array to be formatted
* in the rendered view.
*
* @param object $controller Instantiating controller
* @return void
* @access public
*/
function beforeRender(&$controller) {
if ($this->isRest()) {
if (empty($this->_status['error'])) {
$_response = empty($this->responseVars) ? $controller->viewVars : array_intersect_key($controller->viewVars, Set::normalize($this->responseVars));
} else {
$_response = array('error' => $this->_status['error']);
}
$this->_status['response'] = serialize($_response);
$this->RestLog->save($this->_status);
$controller->set(compact('_response'));
$controller->header(sprintf('HTTP/1.1 %s %s', $this->_status['httpcode'], $this->codes[$this->_status['httpcode']]));
}
}
/**
* Sets error message and returns false.
*
* @param string $message Error message
* @return false
* @access public
*/
function error($message = '') {
$this->_status['error'] = $message;
return false;
}
/**
* Attempts authentication with either an api token or http basic authentication.
* After login is successful, normal AuthComponent authorization is attempted.
*
* @return boolean True if request is authorized, false if otherwise
* @access public
*/
function isAuthorized(&$controller) {
if (!empty($this->tokenField) && !empty($this->params['url']['_token'])) {
$userModel =& $this->Auth->getModel();
$findBy = 'findBy' . Inflection::camelize($this->tokenField);
$user = $userModel->{$findBy}($this->params['url']['_token']);
if (empty($user)) {
return $this->error('Your api key could not be authenticated.');
}
// @TODO: Fix $userModel->primaryKey access bug
// $this->_status['user_id'] = $user[$userModel->alias][$model->primaryKey];
$credentials = array(
'username' => $user[$userModel->alias][$this->Auth->fields['username']],
'password' => $user[$userModel->alias][$this->Auth->fields['password']]
);
if (!$this->login($credentials)) {
return $this->error($this->Auth->loginError);
}
} elseif (isset($this->Security)) {
$credentials = $this->Security->loginCredentials('basic');
if (empty($credentials) || !$this->login($credentials)) {
$this->Security->blackHole($controller, 'login');
}
}
return true;
}
/**
* Attempts to authenticate user with AuthComponent given a username/password combo.
*
* @param array $credentials
* @return boolean
* @access public
*/
function login($credentials = array()) {
$credentials = array_merge(
array(
'username' => '',
'password' => ''
), $credentials
);
extract($credentials);
$userModel =& $this->Auth->getModel();
$data = array(
$userModel->alias . '.' . $this->Auth->fields['username'] => $username,
$userModel->alias . '.' . $this->Auth->fields['password'] => $password
);
return $this->Auth->login($data);
}
/**
* Determines if request is for API.
*
* @return boolean True if API, false if otherwise
* @access public
*/
function isRest() {
return in_array($this->params['url']['ext'], $this->responseTypes);
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment