Add extended response format for API

This commit is contained in:
Nicolas Le Goff
2014-05-30 19:51:58 +02:00
parent a0d0b8f03c
commit e17493aa0b
7 changed files with 188 additions and 171 deletions

View File

@@ -43,6 +43,12 @@ class API_V1_adapter extends API_V1_Abstract
const OBJECT_TYPE_STORY = 'http://api.phraseanet.com/api/objects/story';
const OBJECT_TYPE_STORY_METADATA_BAG = 'http://api.phraseanet.com/api/objects/story-metadata-bag';
public static $extendedContentTypes = array(
'json' => array('application/vnd.phraseanet.record-extended+json'),
'yaml' => array('application/vnd.phraseanet.record-extended+yaml'),
'jsonp' => array('application/vnd.phraseanet.record-extended+jsonp'),
);
/**
* API constructor
*
@@ -848,9 +854,9 @@ class API_V1_adapter extends API_V1_Abstract
foreach ($search_result->getResults() as $record) {
if ($record->is_grouping()) {
$ret['results']['stories'][] = $this->list_story($record);
$ret['results']['stories'][] = $this->list_story($record, $request->get('_extended'));
} else {
$ret['results']['records'][] = $this->list_record($record);
$ret['results']['records'][] = $this->list_record($record, $request->get('_extended'));
}
}
@@ -878,7 +884,7 @@ class API_V1_adapter extends API_V1_Abstract
list($ret, $search_result) = $this->prepare_search_request($request);
foreach ($search_result->getResults() as $record) {
$ret['results'][] = $this->list_record($record);
$ret['results'][] = $this->list_record($record, $request->get('_extended'));
}
/**
@@ -958,8 +964,8 @@ class API_V1_adapter extends API_V1_Abstract
$record = $this->app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id);
$stories = array_map(function ($story) use ($that) {
return $that->list_story($story);
$stories = array_map(function ($story) use ($that, $request) {
return $that->list_story($story, $request->get('_extended'));
}, array_values($record->get_grouping_parents()->get_elements()));
$result->set_datas(array(
@@ -1177,7 +1183,7 @@ class API_V1_adapter extends API_V1_Abstract
$collection = collection::get_from_base_id($this->app, $request->get('base_id'));
$record->move_to_collection($collection, $this->app['phraseanet.appbox']);
$result->set_datas(array("record" => $this->list_record($record)));
$result->set_datas(array("record" => $this->list_record($record, $request->get('_extended'))));
} catch (\Exception $e) {
$result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, $e->getMessage());
}
@@ -1199,7 +1205,7 @@ class API_V1_adapter extends API_V1_Abstract
$databox = $this->app['phraseanet.appbox']->get_databox($databox_id);
try {
$record = $databox->get_record($record_id);
$result->set_datas(array('record' => $this->list_record($record)));
$result->set_datas(array('record' => $this->list_record($record, $request->get('_extended'))));
} catch (NotFoundHttpException $e) {
$result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('Record Not Found'));
} catch (\Exception $e) {
@@ -1223,7 +1229,7 @@ class API_V1_adapter extends API_V1_Abstract
$databox = $this->app['phraseanet.appbox']->get_databox($databox_id);
try {
$story = $databox->get_record($story_id);
$result->set_datas(array('story' => $this->list_story($story)));
$result->set_datas(array('story' => $this->list_story($story, $request->get('_extended'))));
} catch (NotFoundHttpException $e) {
$result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('Story Not Found'));
} catch (\Exception $e) {
@@ -1339,7 +1345,7 @@ class API_V1_adapter extends API_V1_Abstract
$result->set_datas(
array(
"basket" => $this->list_basket($Basket),
"basket_elements" => $this->list_basket_content($Basket)
"basket_elements" => $this->list_basket_content($Basket, $request->get('_extended'))
)
);
@@ -1352,12 +1358,12 @@ class API_V1_adapter extends API_V1_Abstract
* @param \Entities\Basket $Basket
* @return type
*/
protected function list_basket_content(\Entities\Basket $Basket)
protected function list_basket_content(\Entities\Basket $Basket, $extended = false)
{
$ret = array();
foreach ($Basket->getElements() as $basket_element) {
$ret[] = $this->list_basket_element($basket_element);
$ret[] = $this->list_basket_element($basket_element, $extended);
}
return $ret;
@@ -1369,12 +1375,12 @@ class API_V1_adapter extends API_V1_Abstract
* @param \Entities\BasketElement $basket_element
* @return type
*/
protected function list_basket_element(\Entities\BasketElement $basket_element)
protected function list_basket_element(\Entities\BasketElement $basket_element, $extended = false)
{
$ret = array(
'basket_element_id' => $basket_element->getId(),
'order' => $basket_element->getOrd(),
'record' => $this->list_record($basket_element->getRecord($this->app)),
'record' => $this->list_record($basket_element->getRecord($this->app), $extended),
'validation_item' => null != $basket_element->getBasket()->getValidation(),
);
@@ -1528,7 +1534,7 @@ class API_V1_adapter extends API_V1_Abstract
'feed' => $this->list_publication($feed, $user),
'offset_start' => $offset_start,
'per_page' => $per_page,
'entries' => $this->list_publications_entries($feed, $offset_start, $per_page),
'entries' => $this->list_publications_entries($feed, $request->get('_extended'), $offset_start, $per_page),
);
$result->set_datas($datas);
@@ -1553,7 +1559,7 @@ class API_V1_adapter extends API_V1_Abstract
'total_entries' => $feed->get_count_total_entries(),
'offset_start' => $offset_start,
'per_page' => $per_page,
'entries' => $this->list_publications_entries($feed, $offset_start, $per_page),
'entries' => $this->list_publications_entries($feed, $request->get('_extended'), $offset_start, $per_page),
));
return $result;
@@ -1611,14 +1617,13 @@ class API_V1_adapter extends API_V1_Abstract
* @param int $how_many
* @return array
*/
protected function list_publications_entries(Feed_Abstract $feed, $offset_start = 0, $how_many = 5)
protected function list_publications_entries(Feed_Abstract $feed, $extended = false, $offset_start = 0, $how_many = 5)
{
$entries = $feed->get_entries($offset_start, $how_many)->get_entries();
$out = array();
foreach ($entries as $entry) {
$out[] = $this->list_publication_entry($entry);
$out[] = $this->list_publication_entry($entry, $extended);
}
return $out;
@@ -1630,11 +1635,11 @@ class API_V1_adapter extends API_V1_Abstract
* @param Feed_Entry_Adapter $entry
* @return array
*/
protected function list_publication_entry(Feed_Entry_Adapter $entry)
protected function list_publication_entry(Feed_Entry_Adapter $entry, $extended = false)
{
$items = array();
foreach ($entry->get_content() as $item) {
$items[] = $this->list_publication_entry_item($item);
$items[] = $this->list_publication_entry_item($item, $extended);
}
return array(
@@ -1659,11 +1664,11 @@ class API_V1_adapter extends API_V1_Abstract
* @param Feed_Entry_Item $item
* @return array
*/
protected function list_publication_entry_item(Feed_Entry_Item $item)
protected function list_publication_entry_item(Feed_Entry_Item $item, $extended = false)
{
$datas = array(
'item_id' => $item->get_id()
, 'record' => $this->list_record($item->get_record())
'item_id' => $item->get_id(),
'record' => $this->list_record($item->get_record(), $extended)
);
return $datas;
@@ -1874,7 +1879,7 @@ class API_V1_adapter extends API_V1_Abstract
* @param record_adapter $record
* @return array
*/
public function list_record(record_adapter $record)
public function list_record(record_adapter $record, $extended = false)
{
$technicalInformation = array();
foreach ($record->get_technical_infos() as $name => $value) {
@@ -1884,7 +1889,7 @@ class API_V1_adapter extends API_V1_Abstract
);
}
return array(
$data = array(
'databox_id' => $record->get_sbas_id(),
'record_id' => $record->get_record_id(),
'mime_type' => $record->get_mime(),
@@ -1899,6 +1904,45 @@ class API_V1_adapter extends API_V1_Abstract
'phrasea_type' => $record->get_type(),
'uuid' => $record->get_uuid(),
);
if ($extended) {
$subdefs = $caption = array();
foreach ($record->get_embedable_medias(array(), array()) as $name => $media) {
$subdefs[] = $this->list_embedable_media($media, $this->app['phraseanet.registry']);
}
$fields = $record->get_caption()->get_fields();
foreach ($fields as $field) {
$caption[] = array(
'meta_structure_id' => $field->get_meta_struct_id(),
'name' => $field->get_name(),
'value' => $field->get_serialized_values(';'),
);
}
$that = $this;
$baskets = array_map(function ($basket) use ($that, $record) {
return $that->list_basket($basket);
}, (array) $record->get_container_baskets($this->app['EM'], $this->app['authentication']->getUser())
);
$stories = array_map(function ($story) use ($that, $extended) {
return $that->list_story($story, $extended);
}, array_values($record->get_grouping_parents()->get_elements()));
$extendedData = array(
'subdefs' => $subdefs,
'metadata' => $this->list_record_caption($record->get_caption()),
'status' => $this->list_record_status($record->get_databox(), $record->get_status()),
// 'baskets' => $baskets,
// 'stories' => $stories,
'caption' => $caption
);
$data = array_merge($data, $extendedData);
}
return $data;
}
/**
@@ -1908,15 +1952,15 @@ class API_V1_adapter extends API_V1_Abstract
*
* @return array
*/
public function list_story(record_adapter $story)
public function list_story(record_adapter $story, $extended = false)
{
if (!$story->is_grouping()) {
throw new \API_V1_exception_notfound('Story not found');
}
$that = $this;
$records = array_map(function (\record_adapter $record) use ($that) {
return $that->list_record($record);
$records = array_map(function (\record_adapter $record) use ($that, $extended) {
return $that->list_record($record, $extended);
}, array_values($story->get_children()->get_elements()));
$caption = $story->get_caption();

View File

@@ -14,77 +14,52 @@ use Alchemy\Phrasea\Core\PhraseaEvents;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Yaml\Dumper;
class API_V1_result
{
protected $app;
/**
*
* @var string
*/
/** @var string */
protected $api_version;
/**
*
* @var string
*/
/** @var string */
protected $response_time;
/**
*
* @var int
*/
/** @var int */
protected $http_code = 200;
/**
*
* @var string
*/
/** @var string */
protected $error_type;
/**
*
* @var string
*/
/** @var string */
protected $error_message;
/**
*
* @var string
*/
/** @var string */
protected $error_details;
/**
*
* @var string
*/
/** @var string */
protected $request;
/**
*
* @var mixed
*/
/** @var mixed */
protected $response;
/**
*
* @var string
*/
/** @var string */
protected $response_type;
/**
* Constant for responsetype json
*/
/** Constant for response type json */
const FORMAT_JSON = 'json';
/**
* Constant for responsetype yaml
*/
/** Constant for response type yaml */
const FORMAT_YAML = 'yaml';
/**
* Constant for responsetype jsonp
*/
/** Constant for response type jsonp */
const FORMAT_JSONP = 'jsonp';
/** Constant for response type json+extended */
const FORMAT_JSON_EXTENDED = 'json+extended';
/** Constant for response type yaml+extended */
const FORMAT_YAML_EXTENDED = 'yaml+extended';
/** Constant for response type jsonp+extended */
const FORMAT_JSONP_EXTENDED = 'jsonp+extended';
const ERROR_BAD_REQUEST = 'Bad Request';
const ERROR_UNAUTHORIZED = 'Unauthorized';
const ERROR_FORBIDDEN = 'Forbidden';
@@ -92,6 +67,7 @@ class API_V1_result
const ERROR_MAINTENANCE = 'Service Temporarily Unavailable';
const ERROR_METHODNOTALLOWED = 'Method Not Allowed';
const ERROR_INTERNALSERVERERROR = 'Internal Server Error';
const ERROR_UNACCEPTABLE = 'Unacceptable';
/**
* API v1 Result constructor
@@ -112,37 +88,9 @@ class API_V1_result
$this->response_time = $date->format(DATE_ATOM);
$this->response = new stdClass();
$this->parse_response_type();
return $this;
}
protected function parse_response_type()
{
if (trim($this->request->get('callback')) !== '') {
return $this->response_type = self::FORMAT_JSONP;
}
$accept = $this->request->getAcceptableContentTypes();
$response_types = array();
foreach ($accept as $key => $app_type) {
$response_types[strtolower($app_type)] = true;
}
if (array_key_exists('application/json', $response_types)) {
return $this->response_type = self::FORMAT_JSON;
}
if (array_key_exists('application/yaml', $response_types)) {
return $this->response_type = self::FORMAT_YAML;
}
if (array_key_exists('text/yaml', $response_types)) {
return $this->response_type = self::FORMAT_YAML;
}
return $this->response_type = self::FORMAT_JSON;
}
/**
* Set datas to the response
* If no datas provided (aka empty array), a stdClass if set,
@@ -153,8 +101,9 @@ class API_V1_result
*/
public function set_datas(array $datas)
{
if (count($datas) === 0)
if (count($datas) === 0) {
$datas = new stdClass ();
}
$this->response = $datas;
return $this;
@@ -177,16 +126,13 @@ class API_V1_result
*/
public function format()
{
$request_uri = sprintf('%s %s'
, $this->request->getMethod()
, $this->request->getBasePath()
. $this->request->getPathInfo()
);
$ret = array(
'meta' => array(
'api_version' => $this->api_version
, 'request' => $request_uri
, 'request' => sprintf('%s %s',
$this->request->getMethod(),
$this->request->getBasePath() . $this->request->getPathInfo()
)
, 'response_time' => $this->response_time
, 'http_code' => $this->http_code
, 'error_type' => $this->error_type
@@ -207,45 +153,25 @@ class API_V1_result
$return_value = false;
switch ($this->response_type) {
switch ($this->request->getRequestFormat('json')) {
case self::FORMAT_JSON:
case self::FORMAT_JSON_EXTENDED:
default:
$return_value = p4string::jsonencode($ret);
$return_value = \p4string::jsonencode($ret);
break;
case self::FORMAT_YAML:
if ($ret['response'] instanceof stdClass)
case self::FORMAT_YAML_EXTENDED:
if ($ret['response'] instanceof \stdClass) {
$ret['response'] = array();
}
$dumper = new Symfony\Component\Yaml\Dumper();
$dumper = new Dumper();
$return_value = $dumper->dump($ret, 8);
break;
case self::FORMAT_JSONP:
case self::FORMAT_JSONP_EXTENDED:
$callback = trim($this->request->get('callback'));
$return_value = $callback . '(' . p4string::jsonencode($ret) . ')';
break;
}
return $return_value;
}
/**
* Return serailized datas content type
*
* @return string
*/
public function get_content_type()
{
switch ($this->response_type) {
case self::FORMAT_JSON:
default:
$return_value = 'application/json';
break;
case self::FORMAT_YAML:
$return_value = 'application/yaml';
break;
case self::FORMAT_JSONP:
$return_value = 'text/javascript';
$return_value = $callback . '(' . \p4string::jsonencode($ret) . ')';
break;
}
@@ -301,6 +227,10 @@ class API_V1_result
$this->error_type = $const;
$this->error_message = API_V1_exception_maintenance::get_details();
break;
case self::ERROR_UNACCEPTABLE:
$this->http_code = 406;
$this->error_type = $const;
break;
case OAUTH2_ERROR_INVALID_REQUEST:
$this->error_type = $const;
break;
@@ -345,6 +275,10 @@ class API_V1_result
$this->error_type = self::ERROR_METHODNOTALLOWED;
$this->error_message = API_V1_exception_methodnotallowed::get_details();
break;
case 406:
$this->http_code = $code;
$this->error_type = self::ERROR_UNACCEPTABLE;
break;
case 500:
$this->http_code = $code;
$this->error_type = self::ERROR_INTERNALSERVERERROR;
@@ -362,7 +296,7 @@ class API_V1_result
*/
public function get_http_code()
{
if ($this->response_type == self::FORMAT_JSONP && $this->http_code != 500) {
if ($this->response_type == self::FORMAT_JSONP && $this->http_code !== 500) {
return 200;
} else {
return $this->http_code;
@@ -385,11 +319,7 @@ class API_V1_result
*/
public function get_response()
{
$response = new Response(
$this->format(),
$this->get_http_code(),
array('Content-Type' => $this->get_content_type())
);
$response = new Response($this->format(), $this->get_http_code());
$response->setCharset('UTF-8');
return $response;