SAAS-1063: REST API for podcasts

Hierarchy routing is working
Basic implentation of podcast INDEX and POST actions done
This commit is contained in:
drigato 2015-09-16 14:22:13 -04:00
parent a444751397
commit 67db2c1d25
9 changed files with 391 additions and 9 deletions

View file

@ -1,5 +1,7 @@
<?php
require_once 'RouteController.php';
class Rest_Bootstrap extends Zend_Application_Module_Bootstrap
{
protected function _initRouter()
@ -8,9 +10,35 @@ class Rest_Bootstrap extends Zend_Application_Module_Bootstrap
$router = $front->getRouter();
$restRoute = new Zend_Rest_Route($front, array(), array(
'rest'=> array('media', 'show-image')));
'rest'=> array('media', 'show-image', 'podcast', 'podcast-episodes')));
assert($router->addRoute('rest', $restRoute));
$route = new Rest_RouteController($front,
'rest/podcast/:id/episodes',
array(
'controller' => 'podcast-episodes',
'module' => 'rest'
),
array(
'id' => '\d+'
)
);
$router->addRoute('podcast-episodes-index', $route);
$route = new Rest_RouteController($front,
'rest/podcast/:id/episodes/:episode_id',
array(
'controller' => 'podcast-episodes',
'module' => 'rest'
),
array(
'id' => '\d+',
'episode_id' => '\d+'
)
);
$router->addRoute('podcast-episodes', $route);
/** MediaController Routes **/
$downloadRoute = new Zend_Controller_Router_Route(
'rest/media/:id/download',

View file

@ -12,11 +12,39 @@ class Rest_PodcastController extends Zend_Rest_Controller
public function indexAction()
{
$totalPodcastCount = PodcastQuery::create()->count();
// Check if offset and limit were sent with request.
// Default limit to zero and offset to $totalFileCount
$offset = $this->_getParam('offset', 0);
$limit = $this->_getParam('limit', $totalPodcastCount);
//Sorting parameters
$sortColumn = $this->_getParam('sort', PodcastPeer::ID);
$sortDir = $this->_getParam('sort_dir', Criteria::ASC);
$query = PodcastQuery::create()
->setLimit($limit)
->setOffset($offset)
->orderBy($sortColumn, $sortDir);
$queryResult = $query->find();
$podcastArray = array();
foreach ($queryResult as $podcast)
{
array_push($podcastArray, $podcast->toArray(BasePeer::TYPE_FIELDNAME));
}
$this->getResponse()
->setHttpResponseCode(200)
->setHeader('X-TOTAL-COUNT', $totalPodcastCount)
->appendBody(json_encode($podcastArray));
}
public function getAction()
{
Logging::info("podcasts get");
$id = $this->getId();
if (!$id) {
return;
@ -32,17 +60,47 @@ class Rest_PodcastController extends Zend_Rest_Controller
public function postAction()
{
//If we do get an ID on a POST, then that doesn't make any sense
//since POST is only for creating.
if ($id = $this->_getParam('id', false)) {
$resp = $this->getResponse();
$resp->setHttpResponseCode(400);
$resp->appendBody("ERROR: ID should not be specified when using POST. POST is only used for podcast creation, and an ID will be chosen by Airtime");
return;
}
try {
$requestData = json_decode($this->getRequest()->getRawBody(), true);
$podcast = Podcast::create($requestData);
$this->getResponse()
->setHttpResponseCode(201)
->appendBody(json_encode($podcast));
}
catch (PodcastLimitReachedException $e) {
$this->getResponse()
->setHttpResponseCode(400)
->appendBody("ERROR: Podcast limit reached.");
}
catch (InvalidPodcastException $e) {
$this->invalidDataResponse();
Logging::error($e->getMessage());
}
catch (Exception $e) {
$this->unknownErrorResponse();
Logging::error($e->getMessage());
throw $e;
}
}
public function putAction()
{
Logging::info("podcast put");
}
public function deleteAction()
{
Logging::info("delete podcast");
}
private function getId()
@ -56,4 +114,11 @@ class Rest_PodcastController extends Zend_Rest_Controller
return $id;
}
private function unknownErrorResponse()
{
$resp = $this->getResponse();
$resp->setHttpResponseCode(400);
$resp->appendBody("An unknown error occurred.");
}
}

View file

@ -0,0 +1,76 @@
<?php
class Rest_PodcastEpisodesController extends Zend_Rest_Controller
{
public function init()
{
$this->view->layout()->disableLayout();
// Remove reliance on .phtml files to render requests
$this->_helper->viewRenderer->setNoRender(true);
}
public function indexAction()
{
Logging::info("episodes index");
$id = $this->getId();
Logging::info($id);
if (!$id) {
return;
}
}
public function getAction()
{
Logging::info("episodes get");
$id = $this->getId();
if (!$id) {
return;
}
try {
} catch (Exception $e) {
}
}
public function postAction()
{
Logging::info("episodes post");
}
public function putAction()
{
Logging::info("episodes put");
}
public function deleteAction()
{
Logging::info("delete - episodes");
$id = $this->getId();
Logging::info($id);
if (!$id) {
return;
}
}
private function getId()
{
if (!$id = $this->_getParam('episode_id', false)) {
$resp = $this->getResponse();
$resp->setHttpResponseCode(400);
$resp->appendBody("ERROR: No podcast ID specified.");
return false;
}
return $id;
}
private function unknownErrorResponse()
{
$resp = $this->getResponse();
$resp->setHttpResponseCode(400);
$resp->appendBody("An unknown error occurred.");
}
}

View file

@ -0,0 +1,108 @@
<?php
/**
* Class Rest_RouteController
*
* Taken from https://github.com/aporat/Application_Rest_Controller_Route
* to enable hierarchy routing
*/
class Rest_RouteController extends Zend_Controller_Router_Route
{
/**
* @var Zend_Controller_Front
*/
protected $_front;
protected $_actionKey = 'action';
/**
* Prepares the route for mapping by splitting (exploding) it
* to a corresponding atomic parts. These parts are assigned
* a position which is later used for matching and preparing values.
*
* @param Zend_Controller_Front $front Front Controller object
* @param string $route Map used to match with later submitted URL path
* @param array $defaults Defaults for map variables with keys as variable names
* @param array $reqs Regular expression requirements for variables (keys as variable names)
* @param Zend_Translate $translator Translator to use for this instance
*/
public function __construct(Zend_Controller_Front $front, $route, $defaults = array(), $reqs = array(), Zend_Translate $translator = null, $locale = null)
{
$this->_front = $front;
$this->_dispatcher = $front->getDispatcher();
parent::__construct($route, $defaults, $reqs, $translator, $locale);
}
/**
* Matches a user submitted path with parts defined by a map. Assigns and
* returns an array of variables on a successful match.
*
* @param string $path Path used to match against this routing map
* @return array|false An array of assigned values or a false on a mismatch
*/
public function match($path, $partial = false)
{
$return = parent::match($path, $partial);
// add the RESTful action mapping
if ($return) {
$request = $this->_front->getRequest();
$path = $request->getPathInfo();
$params = $request->getParams();
$path = trim($path, self::URI_DELIMITER);
if ($path != '') {
$path = explode(self::URI_DELIMITER, $path);
}
//Store path count for method mapping
$pathElementCount = count($path);
// Determine Action
$requestMethod = strtolower($request->getMethod());
if ($requestMethod != 'get') {
if ($request->getParam('_method')) {
$return[$this->_actionKey] = strtolower($request->getParam('_method'));
} elseif ( $request->getHeader('X-HTTP-Method-Override') ) {
$return[$this->_actionKey] = strtolower($request->getHeader('X-HTTP-Method-Override'));
} else {
$return[$this->_actionKey] = $requestMethod;
}
// Map PUT and POST to actual create/update actions
// based on parameter count (posting to resource or collection)
switch( $return[$this->_actionKey] ){
case 'post':
$return[$this->_actionKey] = 'post';
break;
case 'put':
$return[$this->_actionKey] = 'put';
break;
}
} else {
// if the last argument in the path is a numeric value, consider this request a GET of an item
$lastParam = array_pop($path);
if (is_numeric($lastParam)) {
$return[$this->_actionKey] = 'get';
} else {
$return[$this->_actionKey] = 'index';
}
}
}
return $return;
}
}