diff --git a/composer.json b/composer.json index 87eaa4dde5..7f2c7a1fef 100644 --- a/composer.json +++ b/composer.json @@ -65,7 +65,8 @@ "twig/twig" : "~1.14, >=1.14.2", "twig/extensions" : "~1.0", "vierbergenlars/php-semver" : "~2.1", - "zend/gdata" : "~1.12.1" + "zend/gdata" : "~1.12.1", + "willdurand/negotiation" : "~1.3" }, "require-dev": { "doctrine/data-fixtures" : "1.0.x@dev", diff --git a/composer.lock b/composer.lock index 13b332a281..688f5c3913 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "748dacbcdc2199ab5eed1a237bf4fd17", + "hash": "81820d7853d2c85cbb34fc57910d6963", "packages": [ { "name": "alchemy-fr/tcpdf-clone", @@ -3034,6 +3034,56 @@ ], "time": "2013-09-20 10:41:27" }, + { + "name": "willdurand/negotiation", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/willdurand/Negotiation.git", + "reference": "a98fb6b9808610c1aa326c736893d3d77d9383b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/willdurand/Negotiation/zipball/a98fb6b9808610c1aa326c736893d3d77d9383b6", + "reference": "a98fb6b9808610c1aa326c736893d3d77d9383b6", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-0": { + "Negotiation": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "William Durand", + "email": "william.durand1@gmail.com", + "homepage": "http://www.willdurand.fr" + } + ], + "description": "Content Negotiation tools for PHP provided as a standalone library.", + "homepage": "http://williamdurand.fr/Negotiation/", + "keywords": [ + "accept", + "content", + "format", + "header", + "negotiation" + ], + "time": "2014-05-16 12:34:51" + }, { "name": "zend/gdata", "version": "1.12.1", @@ -4043,6 +4093,7 @@ "php-ffmpeg/php-ffmpeg": 20, "doctrine/data-fixtures": 20 }, + "prefer-stable": false, "platform": { "php": ">=5.3.3" }, diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php index 8c15144e23..779175e4b9 100644 --- a/lib/Alchemy/Phrasea/Application.php +++ b/lib/Alchemy/Phrasea/Application.php @@ -76,6 +76,7 @@ use Alchemy\Phrasea\Core\Provider\BorderManagerServiceProvider; use Alchemy\Phrasea\Core\Provider\CacheServiceProvider; use Alchemy\Phrasea\Core\Provider\ConfigurationServiceProvider; use Alchemy\Phrasea\Core\Provider\ConfigurationTesterServiceProvider; +use Alchemy\Phrasea\Core\Provider\ContentNegotiationServiceProvider; use Alchemy\Phrasea\Core\Provider\CSVServiceProvider; use Alchemy\Phrasea\Core\Provider\FileServeServiceProvider; use Alchemy\Phrasea\Core\Provider\FtpServiceProvider; @@ -301,6 +302,7 @@ class Application extends SilexApplication $this->register(new FileServeServiceProvider()); $this->register(new PluginServiceProvider()); $this->register(new PhraseaEventServiceProvider()); + $this->register(new ContentNegotiationServiceProvider()); $this['phraseanet.exception_handler'] = $this->share(function ($app) { return PhraseaExceptionHandler::register($app['debug']); @@ -394,6 +396,7 @@ class Application extends SilexApplication $dispatcher->addListener(KernelEvents::RESPONSE, array($app, 'addUTF8Charset'), -128); $dispatcher->addSubscriber($app['phraseanet.logout-subscriber']); $dispatcher->addSubscriber($app['phraseanet.locale-subscriber']); + $dispatcher->addSubscriber($app['phraseanet.content-negotiation-subscriber']); $dispatcher->addSubscriber($app['phraseanet.maintenance-subscriber']); $dispatcher->addSubscriber($app['phraseanet.cookie-disabler-subscriber']); $dispatcher->addSubscriber($app['phraseanet.session-manager-subscriber']); diff --git a/lib/Alchemy/Phrasea/Application/Api.php b/lib/Alchemy/Phrasea/Application/Api.php index d51c6cd070..f2eb7888c1 100644 --- a/lib/Alchemy/Phrasea/Application/Api.php +++ b/lib/Alchemy/Phrasea/Application/Api.php @@ -24,9 +24,9 @@ use Monolog\Logger; use Monolog\Processor\WebProcessor; use Silex\Application as SilexApplication; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) { - $app = new PhraseaApplication($environment); $app->loadPlugins(); @@ -39,6 +39,50 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) { return $monolog; })); + // handle API content negotiation + $app->before(function(Request $request) use ($app) { + // register custom API format + $request->setFormat(\API_V1_result::FORMAT_JSON_EXTENDED, \API_V1_adapter::$extendedContentTypes['json']); + $request->setFormat(\API_V1_result::FORMAT_YAML_EXTENDED, \API_V1_adapter::$extendedContentTypes['yaml']); + $request->setFormat(\API_V1_result::FORMAT_JSONP_EXTENDED, \API_V1_adapter::$extendedContentTypes['jsonp']); + $request->setFormat(\API_V1_result::FORMAT_JSONP, array('text/javascript', 'application/javascript')); + + // handle content negociation + $priorities = array('application/json', 'application/yaml', 'text/yaml', 'text/javascript', 'application/javascript'); + foreach (\API_V1_adapter::$extendedContentTypes['json'] as $priorities[]); + foreach (\API_V1_adapter::$extendedContentTypes['yaml'] as $priorities[]); + $format = $app['format.negociator']->getBest($request->headers->get('accept') ,$priorities); + + // throw unacceptable http error if API can not handle asked format + if (null === $format) { + $app->abort(406); + } + // set request format according to negotiated content or override format with JSONP if callback parameter is defined + if (trim($request->get('callback')) !== '') { + $request->setRequestFormat(\API_V1_result::FORMAT_JSONP); + } else { + $request->setRequestFormat($request->getFormat($format->getValue())); + } + + // tells whether asked format is extended or not + $request->attributes->set('_extended', in_array( + $request->getRequestFormat(\API_V1_result::FORMAT_JSON), + array( + \API_V1_result::FORMAT_JSON_EXTENDED, + \API_V1_result::FORMAT_YAML_EXTENDED, + \API_V1_result::FORMAT_JSONP_EXTENDED + ) + )); + }, PhraseaApplication::EARLY_EVENT); + + $app->after(function(Request $request, Response $response) use ($app) { + if ($request->getRequestFormat(\API_V1_result::FORMAT_JSON) === \API_V1_result::FORMAT_JSONP && !$response->isOk() && !$response->isServerError()) { + $response->setStatusCode(200); + } + // set response content type + $response->headers->set('Content-Type', $request->getMimeType($request->getRequestFormat(\API_V1_result::FORMAT_JSON))); + }); + $app->register(new \API_V1_Timer()); $app['dispatcher']->dispatch(PhraseaEvents::API_LOAD_START, new ApiLoadStartEvent()); diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriber.php index d9ebf47189..03f62462cb 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriber.php @@ -66,6 +66,8 @@ class ApiExceptionHandlerSubscriber implements EventSubscriberInterface } elseif ($e instanceof HttpExceptionInterface) { if (503 === $e->getStatusCode()) { $code = \API_V1_result::ERROR_MAINTENANCE; + } else if (406 === $e->getStatusCode()) { + $code = \API_V1_result::ERROR_UNACCEPTABLE; } else { $code = \API_V1_result::ERROR_INTERNALSERVERERROR; } diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/ContentNegotiationSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ContentNegotiationSubscriber.php new file mode 100644 index 0000000000..9769e71571 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ContentNegotiationSubscriber.php @@ -0,0 +1,50 @@ +app = $app; + } + + public static function getSubscribedEvents() + { + return array( + KernelEvents::REQUEST => array('onKernelRequest', Application::EARLY_EVENT), + ); + } + + public function onKernelRequest(GetResponseEvent $event) + { + $priorities = array('text/html', 'application/json', '*/*'); + $format = $this->app['format.negociator']->getBest($event->getRequest()->headers->get('accept', '*/*'), $priorities); + + if (null === $format) { + $this->app->abort(406, 'Not acceptable'); + } + + $event->getRequest()->setRequestFormat($event->getRequest()->getFormat($format->getValue())); + } +} diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/PhraseaLocaleSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/PhraseaLocaleSubscriber.php index ef5e53e538..34ecb213cd 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/PhraseaLocaleSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/PhraseaLocaleSubscriber.php @@ -59,18 +59,6 @@ class PhraseaLocaleSubscriber implements EventSubscriberInterface return; } - /** - * add content negotiation here - */ - $contentTypes = $event->getRequest()->getAcceptableContentTypes(); - $event->getRequest()->setRequestFormat( - $event->getRequest()->getFormat( - array_shift( - $contentTypes - ) - ) - ); - $this->app['locale'] = $this->app->share(function (Application $app) use ($event) { if (isset($app['phraseanet.registry'])) { $event->getRequest()->setDefaultLocale( diff --git a/lib/Alchemy/Phrasea/Core/Provider/ContentNegotiationServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/ContentNegotiationServiceProvider.php new file mode 100644 index 0000000000..afcb36ee25 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Provider/ContentNegotiationServiceProvider.php @@ -0,0 +1,40 @@ +share(function ($app) { + return new Negotiator(); + }); + + $app['format.negociator'] = $app->share(function ($app) { + return new FormatNegotiator(); + }); + + $app['langage.negociator'] = $app->share(function ($app) { + return new LanguageNegotiator(); + }); + } + + public function boot(Application $app) + { + } +} diff --git a/lib/Alchemy/Phrasea/Core/Provider/PhraseaEventServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/PhraseaEventServiceProvider.php index 1fda4c978b..ece1f1b21e 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/PhraseaEventServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/PhraseaEventServiceProvider.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\Core\Provider; +use Alchemy\Phrasea\Core\Event\Subscriber\ContentNegotiationSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\CookiesDisablerSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\LogoutSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\MaintenanceSubscriber; @@ -38,6 +39,9 @@ class PhraseaEventServiceProvider implements ServiceProviderInterface $app['phraseanet.session-manager-subscriber'] = $app->share(function (Application $app) { return new SessionManagerSubscriber($app); }); + $app['phraseanet.content-negotiation-subscriber'] = $app->share(function (Application $app) { + return new ContentNegotiationSubscriber($app); + }); } public function boot(Application $app) diff --git a/lib/classes/API/V1/adapter.php b/lib/classes/API/V1/adapter.php index 2660433459..5e470d9ee3 100644 --- a/lib/classes/API/V1/adapter.php +++ b/lib/classes/API/V1/adapter.php @@ -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 * @@ -846,9 +852,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')); } } @@ -876,7 +882,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')); } /** @@ -956,8 +962,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( @@ -1175,7 +1181,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()); } @@ -1197,7 +1203,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) { @@ -1221,7 +1227,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) { @@ -1337,7 +1343,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')) ) ); @@ -1350,12 +1356,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; @@ -1367,12 +1373,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(), ); @@ -1526,7 +1532,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); @@ -1551,7 +1557,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; @@ -1609,14 +1615,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; @@ -1628,11 +1633,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( @@ -1657,11 +1662,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; @@ -1872,7 +1877,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) { @@ -1882,7 +1887,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(), @@ -1897,6 +1902,33 @@ 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']); + } + + foreach ($record->get_caption()->get_fields() as $field) { + $caption[] = array( + 'meta_structure_id' => $field->get_meta_struct_id(), + 'name' => $field->get_name(), + 'value' => $field->get_serialized_values(';'), + ); + } + + $extendedData = array( + 'subdefs' => $subdefs, + 'metadata' => $this->list_record_caption($record->get_caption()), + 'status' => $this->list_record_status($record->get_databox(), $record->get_status()), + 'caption' => $caption + ); + + $data = array_merge($data, $extendedData); + } + + return $data; } /** @@ -1906,15 +1938,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(); diff --git a/lib/classes/API/V1/result.php b/lib/classes/API/V1/result.php index 04c69ed86c..dfef2bf645 100644 --- a/lib/classes/API/V1/result.php +++ b/lib/classes/API/V1/result.php @@ -14,77 +14,49 @@ 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 - */ - 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 +64,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 +85,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 +98,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 +123,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 +150,25 @@ class API_V1_result $return_value = false; - switch ($this->response_type) { + switch ($this->request->getRequestFormat(self::FORMAT_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 +224,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 +272,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,11 +293,7 @@ class API_V1_result */ public function get_http_code() { - if ($this->response_type == self::FORMAT_JSONP && $this->http_code != 500) { - return 200; - } else { - return $this->http_code; - } + return $this->http_code; } /** @@ -385,11 +312,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; diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriberTest.php index 667ee18000..8c617d7348 100644 --- a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriberTest.php +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriberTest.php @@ -29,7 +29,6 @@ class ApiExceptionHandlerSubscriberTest extends \PHPUnit_Framework_TestCase $client->request('GET', '/'); $this->assertEquals($code, $client->getResponse()->getStatusCode()); - $this->assertEquals('application/json', $client->getResponse()->headers->get('content-type')); } public function provideExceptionsAndCode() diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ContentNegotiationSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ContentNegotiationSubscriberTest.php new file mode 100644 index 0000000000..dd6102a36d --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ContentNegotiationSubscriberTest.php @@ -0,0 +1,49 @@ +request($negotiationHeader, $expectedContentType); + $this->assertArrayHasKey('content-type', $response->headers->all()); + $this->assertEquals($expectedContentType, $response->headers->get('content-type')); + } + + public function negotiationProvider() + { + return array( + array('text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'text/html; charset=UTF-8'), + array('application/xml,application/xhtml+xml,text/html;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5', 'text/html; charset=UTF-8'), + array('image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/msword, */*', 'text/html; charset=UTF-8'), + array('application/json, */*', 'application/json') + ); + } + + private function request($accept) + { + $app = new Application('test'); + $app['dispatcher']->addSubscriber(new ContentNegotiationSubscriber($app)); + $app->get('/content/negociation', function () { + return ''; + }); + $client = new Client($app); + $client->request('GET', '/content/negociation', + array(), + array(), + array( + 'HTTP_Accept' => $accept + ) + ); + + return $client->getResponse(); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Core/Provider/ContentNegotiationServiceProviderTest.php b/tests/Alchemy/Tests/Phrasea/Core/Provider/ContentNegotiationServiceProviderTest.php new file mode 100644 index 0000000000..79defe4d14 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Provider/ContentNegotiationServiceProviderTest.php @@ -0,0 +1,30 @@ +object->get_error_code($request, 400); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(400, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $result = $this->object->get_error_code($request, 403); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(403, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $result = $this->object->get_error_code($request, 500); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(500, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $result = $this->object->get_error_code($request, 405); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(405, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $result = $this->object->get_error_code($request, 404); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(404, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $result = $this->object->get_error_code($request, 401); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(401, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); } public function testGet_error_message() @@ -58,32 +52,26 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $result = $this->object->get_error_message($request, API_V1_result::ERROR_BAD_REQUEST, 'detaillage'); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(400, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $result = $this->object->get_error_message($request, API_V1_result::ERROR_FORBIDDEN, 'detaillage'); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(403, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $result = $this->object->get_error_message($request, API_V1_result::ERROR_INTERNALSERVERERROR, 'detaillage'); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(500, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $result = $this->object->get_error_message($request, API_V1_result::ERROR_METHODNOTALLOWED, 'detaillage'); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(405, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $result = $this->object->get_error_message($request, API_V1_result::ERROR_NOTFOUND, 'detaillage'); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(404, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $result = $this->object->get_error_message($request, API_V1_result::ERROR_UNAUTHORIZED, 'detaillage'); $this->assertTrue(is_array(json_decode($result->format(), true))); $this->assertEquals(401, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); } public function testGet_version() @@ -96,7 +84,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->get_databoxes($request); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); } @@ -106,7 +93,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract foreach (self::$DI['app']['phraseanet.appbox']->get_databoxes() as $databox) { $result = $this->object->get_databox_collections($request, $databox->get_sbas_id()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); } } @@ -121,7 +107,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->get_record($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); } @@ -131,7 +116,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract foreach (self::$DI['app']['phraseanet.appbox']->get_databoxes() as $databox) { $result = $this->object->get_databox_status($request, $databox->get_sbas_id()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); } } @@ -142,7 +126,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract foreach (self::$DI['app']['phraseanet.appbox']->get_databoxes() as $databox) { $result = $this->object->get_databox_metadatas($request, $databox->get_sbas_id()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); } } @@ -153,7 +136,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract foreach (self::$DI['app']['phraseanet.appbox']->get_databoxes() as $databox) { $result = $this->object->get_databox_terms($request, $databox->get_sbas_id()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); } } @@ -167,7 +149,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array('record_type' => "image", 'search_type' => 0), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->search_records($request); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); $data = json_decode($result->format(), true); @@ -190,7 +171,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->search_records($request); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); $data = json_decode($result->format(), true); @@ -251,7 +231,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array('search_type' => 1), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->search_records($request); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); $data = json_decode($result->format(), true); @@ -283,7 +262,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array('search_type' => 1), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->search($request); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); $data = json_decode($result->format(), true); @@ -314,7 +292,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array('search_type' => 0), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->search($request); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); $data = json_decode($result->format(), true); @@ -353,7 +330,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->get_record_related($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); $data = json_decode($result->format(), true); @@ -392,7 +368,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->get_record_metadatas($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); } @@ -403,7 +378,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->get_record_status($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); } @@ -413,7 +387,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->get_record_embed($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); } @@ -540,7 +513,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->search_baskets($request); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); } @@ -549,7 +521,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array('name' => 'BIG BASKET'), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->create_basket($request); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); $n = 0; @@ -586,7 +557,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->delete_basket($request, $ssel_id); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); $repo = $em->getRepository('\Entities\Basket'); @@ -608,7 +578,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array(), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->get_basket($request, $basket->getId()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); } @@ -621,7 +590,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array('name' => 'PROUTO'), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->set_basket_title($request, $basket->getId()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); $repository = self::$DI['app']['EM']->getRepository('\Entities\Basket'); @@ -640,7 +608,6 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract $request = new Request(array(), array(), array('description' => 'une belle description'), array(), array(), array('HTTP_Accept' => 'application/json')); $result = $this->object->set_basket_description($request, $basket->getId()); $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); $this->assertTrue(is_array(json_decode($result->format(), true))); $repository = self::$DI['app']['EM']->getRepository('\Entities\Basket'); diff --git a/tests/classes/api/v1/api_v1_resultTest.php b/tests/classes/api/v1/api_v1_resultTest.php index 08cb107422..51041dfead 100644 --- a/tests/classes/api/v1/api_v1_resultTest.php +++ b/tests/classes/api/v1/api_v1_resultTest.php @@ -32,157 +32,9 @@ class API_V1_resultTest extends PhraseanetPHPUnitAuthenticatedAbstract $this->assertObjectHasAttribute('time', $timer); } - public function testFormatJson() - { - $server = array( - "HTTP_ACCEPT" => "application/json" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ); - $request = new Request(array("callback" => ""), array(), array(), array(), array(), $server); - - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $return = $api_result->format(); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $return); - $response = json_decode($return); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_OBJECT, $response); - $this->assertObjectHasAttribute("meta", $response); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_OBJECT, $response->meta); - $this->assertObjectHasAttribute("response", $response); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_OBJECT, $response->response); - $this->assertEquals(0, sizeof(get_object_vars($response->response))); - $this->assertEquals(0, sizeof(get_class_methods($response->response))); - $this->checkResponseFieldMeta($response, "api_version", "my_super_version1.0", PHPUnit_Framework_Constraint_IsType::TYPE_STRING); - $this->checkResponseFieldMeta($response, "request", "GET my/base/path/my/request/uri", PHPUnit_Framework_Constraint_IsType::TYPE_STRING); - - $this->assertObjectHasAttribute("timers", $response); - $this->assertCount(1, $response->timers); - - foreach ($response->timers as $timer) { - $this->assertIsTimer($timer); - } - - $date = new \DateTime(); - $now = $date->format('U'); - - $date_query = \DateTime::createFromFormat(DATE_ATOM, $response->meta->response_time); - $now_query = $date_query->format('U'); - - $this->assertLessThan(1, $now_query - $now); - - $this->assertDateAtom($response->meta->response_time); - $date = new DateTime(); - $now_U = $date->format('U'); - $date_resp = DateTime::createFromFormat(DATE_ATOM, $response->meta->response_time); - $resp_U = $date_resp->format('U'); - - $this->assertLessThan(3, abs($resp_U - $now_U), 'No more than 3sec between now and the query'); - - $this->checkResponseFieldMeta($response, "http_code", 200, PHPUnit_Framework_Constraint_IsType::TYPE_INT); - $this->checkResponseFieldMeta($response, "charset", "UTF-8", PHPUnit_Framework_Constraint_IsType::TYPE_STRING); - $this->assertObjectHasAttribute("error_message", $response->meta); - $this->assertNull($response->meta->error_message); - $this->assertObjectHasAttribute("error_details", $response->meta); - $this->assertNull($response->meta->error_details); - - $this->assertObjectHasAttribute("timers", $response); - $this->assertCount(1, $response->timers); - - foreach ($response->timers as $timer) { - $this->assertIsTimer($timer); - } - } - - public function testFormatYaml() - { - $server = array( - "HTTP_ACCEPT" => "application/yaml" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ); - $request = new Request(array("callback" => ""), array(), array(), array(), array(), $server); - - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $return = $api_result->format(); - $sfYaml = new Symfony\Component\Yaml\Parser(); - $response = $sfYaml->parse($return); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $response); - $this->assertArrayHasKey("meta", $response); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $response["meta"]); - $this->assertArrayHasKey("response", $response); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $response["response"]); - $this->assertEquals(0, count($response["response"])); - $this->assertArrayHasKey("api_version", $response["meta"]); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["api_version"]); - $this->assertEquals("my_super_version1.0", $response["meta"]["api_version"]); - $this->assertArrayHasKey("request", $response["meta"]); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["request"]); - $this->assertEquals("GET my/base/path/my/request/uri", $response["meta"]["request"]); - $this->assertArrayHasKey("response_time", $response["meta"]); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["response_time"]); - - $this->assertDateAtom($response["meta"]["response_time"]); - $date_obj1 = DateTime::createFromFormat(DATE_ATOM, $response["meta"]["response_time"]); - $date_obj2 = new DateTime(); - $this->assertLessThan(3, abs($date_obj1->format('U') - $date_obj2->format('U')), 'No more than 3sec between now and the query'); - - $this->assertArrayHasKey("http_code", $response["meta"]); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_INT, $response["meta"]["http_code"]); - $this->assertEquals(200, $response["meta"]["http_code"]); - $this->assertArrayHasKey("error_message", $response["meta"]); - $this->assertNull($response["meta"]["error_message"]); - $this->assertArrayHasKey("error_details", $response["meta"]); - $this->assertNull($response["meta"]["error_details"]); - $this->assertArrayHasKey("charset", $response["meta"]); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["charset"]); - $this->assertEquals("UTF-8", $response["meta"]["charset"]); - - $this->assertArrayHasKey("timers", $response); - $this->assertCount(1, $response['timers']); - } - - public function testFormatJsonP() - { - $server = array( - "HTTP_ACCEPT" => "application/yaml" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ); - $request = new Request(array("callback" => "my_callback_function"), array(), array(), array(), array(), $server); - - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $return = $api_result->format(); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $return); - $this->assertRegexp("/my_callback_function\(\{.+\}\)/", $return); - $response = json_decode(substr($return, 21, strlen($return) - 22)); - - $this->assertObjectHasAttribute("timers", $response); - $this->assertCount(1, $response->timers); - - foreach ($response->timers as $timer) { - $this->assertIsTimer($timer); - } - } - - /** - * @depends testFormatJson - */ public function testSet_datas() { - $server = array( - "HTTP_ACCEPT" => "application/json" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ); - $request = new Request(array("callback" => ""), array(), array(), array(), array(), $server); + $request = new Request(); $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); $api_result->set_datas(array("pirouette" => "cacahuete", "black" => true, "bob" => array("bob"))); @@ -194,14 +46,7 @@ class API_V1_resultTest extends PhraseanetPHPUnitAuthenticatedAbstract public function testGet_datas() { - $server = array( - "HTTP_ACCEPT" => "application/json" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ); - $request = new Request(array("callback" => ""), array(), array(), array(), array(), $server); + $request = new Request(); $data = array("pirouette" => "cacahuete", "black" => true, "bob" => array("bob")); $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); @@ -212,14 +57,7 @@ class API_V1_resultTest extends PhraseanetPHPUnitAuthenticatedAbstract public function testGet_Emptydatas() { - $server = array( - "HTTP_ACCEPT" => "application/json" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ); - $request = new Request(array("callback" => ""), array(), array(), array(), array(), $server); + $request = new Request(); $data = array(); $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); @@ -242,37 +80,6 @@ class API_V1_resultTest extends PhraseanetPHPUnitAuthenticatedAbstract $this->assertEquals($expected_value, $response->response->$field); } - public function testGet_content_type() - { - $server = array("HTTP_ACCEPT" => "application/json"); - $request = new Request(array("callback" => ""), array(), array(), array(), array(), $server); - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $this->assertEquals("application/json", $api_result->get_content_type()); - - $server = array("HTTP_ACCEPT" => "application/yaml"); - $request = new Request(array("callback" => ""), array(), array(), array(), array(), $server); - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $this->assertEquals('application/yaml', $api_result->get_content_type()); - - $server = array("HTTP_ACCEPT" => "text/yaml"); - $request = new Request(array("callback" => ""), array(), array(), array(), array(), $server); - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $this->assertEquals('application/yaml', $api_result->get_content_type()); - - $server = array("HTTP_ACCEPT" => ""); - $request = new Request(array("callback" => "hello"), array(), array(), array(), array(), $server); - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $this->assertEquals('text/javascript', $api_result->get_content_type()); - - $server = array("HTTP_ACCEPT" => "unknow"); - $request = new Request(array("callback" => ""), array(), array(), array(), array(), $server); - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $this->assertEquals("application/json", $api_result->get_content_type()); - } - - /** - * @depends testFormatJson - */ public function testSet_error_message() { $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); @@ -331,9 +138,6 @@ class API_V1_resultTest extends PhraseanetPHPUnitAuthenticatedAbstract } } - /** - * @depends testFormatJson - */ public function testSet_error_code() { $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); @@ -386,14 +190,6 @@ class API_V1_resultTest extends PhraseanetPHPUnitAuthenticatedAbstract $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); $api_result->set_error_code(500); $this->assertEquals(500, $api_result->get_http_code()); - - $api_result = new API_V1_result(self::$DI['app'], new Request(array("callback" => "my_callback")), $this->api); - $api_result->set_error_code(400); - $this->assertEquals(200, $api_result->get_http_code()); - - $api_result = new API_V1_result(self::$DI['app'], new Request(array("callback" => "my_callback")), $this->api); - $api_result->set_error_code(500); - $this->assertEquals(500, $api_result->get_http_code()); } public function testSet_http_code() @@ -408,24 +204,5 @@ class API_V1_resultTest extends PhraseanetPHPUnitAuthenticatedAbstract $this->assertEquals(401, $api_result->get_http_code()); $api_result->set_http_code(403); $this->assertEquals(403, $api_result->get_http_code()); - - $api_result = new API_V1_result(self::$DI['app'], new Request(array("callback" => "my_callback")), $this->api); - $api_result->set_http_code(500); - $this->assertEquals(500, $api_result->get_http_code()); - - $api_result->set_http_code(400); - $this->assertEquals(200, $api_result->get_http_code()); - - $api_result->set_http_code(401); - $this->assertEquals(200, $api_result->get_http_code()); - - $api_result->set_http_code(403); - $this->assertEquals(200, $api_result->get_http_code()); - - $api_result->set_http_code(404); - $this->assertEquals(200, $api_result->get_http_code()); - - $api_result->set_http_code(405); - $this->assertEquals(200, $api_result->get_http_code()); } }