Created
July 8, 2010 16:47
-
-
Save jaredhoyt/468292 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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