Commit c1b39526 authored by alexpott's avatar alexpott

Issue #1891202 by damiankloip, klausi, dawehner: REST Export Views format should be configurable.

parent babb2b71
......@@ -7,11 +7,12 @@
namespace Drupal\rest\Plugin\views\display;
use Symfony\Component\HttpFoundation\Response;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Annotation\Translation;
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\display\PathPluginBase;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouteCollection;
/**
* The plugin that handles Data response callbacks for REST resources.
......@@ -69,7 +70,7 @@ class RestExport extends PathPluginBase {
protected $mimeType;
/**
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::initDisplay().
* {@inheritdoc}
*/
public function initDisplay(ViewExecutable $view, array &$display, array &$options = NULL) {
parent::initDisplay($view, $display, $options);
......@@ -81,7 +82,8 @@ public function initDisplay(ViewExecutable $view, array &$display, array &$optio
$request_content_type = $negotiation->getContentType($request);
// Only use the requested content type if it's not 'html'. If it is then
// default to 'json' to aid debugging.
if ($request_content_type !== 'html') {
// @todo Remove the need for this when we have better content negotiation.
if ($request_content_type != 'html') {
$this->setContentType($request_content_type);
}
......@@ -89,21 +91,21 @@ public function initDisplay(ViewExecutable $view, array &$display, array &$optio
}
/**
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::getType().
* {@inheritdoc}
*/
protected function getType() {
return 'data';
}
/**
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::usesExposed().
* {@inheritdoc}
*/
public function usesExposed() {
return FALSE;
}
/**
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::displaysExposed().
* {@inheritdoc}
*/
public function displaysExposed() {
return FALSE;
......@@ -122,7 +124,7 @@ public function setMimeType($mime_type) {
/**
* Gets the mime type.
*
* This will return any overriden mime type, otherwise returns the mime type
* This will return any overridden mime type, otherwise returns the mime type
* from the request.
*
* @return string
......@@ -153,7 +155,7 @@ public function getContentType() {
}
/**
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::defineOptions().
* {@inheritdoc}
*/
protected function defineOptions() {
$options = parent::defineOptions();
......@@ -173,7 +175,7 @@ protected function defineOptions() {
}
/**
* Overrides \Drupal\views\Plugin\views\display\PathPluginBase::optionsSummary().
* {@inheritdoc}
*/
public function optionsSummary(&$categories, &$options) {
parent::optionsSummary($categories, $options);
......@@ -200,10 +202,27 @@ public function optionsSummary(&$categories, &$options) {
unset($options['css_class']);
}
/**
* {@inheritdoc}
*/
public function collectRoutes(RouteCollection $collection) {
parent::collectRoutes($collection);
$style_plugin = $this->getPlugin('style');
// REST exports should only respond to get methods.
$requirements = array('_method' => 'GET');
// Format as a string using pipes as a delimeter.
$requirements['_format'] = implode('|', $style_plugin->getFormats());
// Add the new requirements to each route.
foreach ($collection as $route) {
$route->addRequirements($requirements);
}
}
/**
* Overrides \Drupal\views\Plugin\views\display\PathPluginBase::execute().
* {@inheritdoc}
*/
public function execute() {
parent::execute();
......@@ -213,7 +232,7 @@ public function execute() {
}
/**
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::render().
* {@inheritdoc}
*/
public function render() {
$build = array();
......@@ -230,7 +249,7 @@ public function render() {
}
/**
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::preview().
* {@inheritdoc}
*
* The DisplayPluginBase preview method assumes we will be returning a render
* array. The data plugin will already return the serialized string.
......
......@@ -12,6 +12,8 @@
use Drupal\views\Plugin\views\style\StylePluginBase;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Annotation\Translation;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Serializer\SerializerInterface;
/**
* The style plugin for serialized output formats.
......@@ -46,17 +48,72 @@ class Serializer extends StylePluginBase {
protected $serializer;
/**
* Overrides \Drupal\views\Plugin\views\style\StylePluginBase::init().
* The available serialization formats.
*
* @var array
*/
protected $formats = array();
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('serializer'),
$container->getParameter('serializer.formats')
);
}
/**
* Constructs a Plugin object.
*/
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
parent::init($view, $display, $options);
public function __construct(array $configuration, $plugin_id, array $plugin_definition, SerializerInterface $serializer, array $serializer_formats) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
// Get the serializer service.
$this->serializer = drupal_container()->get('serializer');
$this->definition = $plugin_definition + $configuration;
$this->serializer = $serializer;
$this->formats = $serializer_formats;
}
/**
* Overrides \Drupal\views\Plugin\views\style\StylePluginBase::render().
* {@inheritdoc}
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['formats'] = array('default' => array());
return $options;
}
/**
* {@inheritdoc}
*/
public function buildOptionsForm(&$form, &$form_state) {
parent::buildOptionsForm($form, $form_state);
$form['formats'] = array(
'#type' => 'checkboxes',
'#title' => t('Accepted request formats'),
'#description' => t('Request formats that will be allowed in responses. If none are selected all formats will be allowed.'),
'#options' => drupal_map_assoc($this->formats),
'#default_value' => $this->options['formats'],
);
}
/**
* {@inheritdoc}
*/
public function submitOptionsForm(&$form, &$form_state) {
parent::submitOptionsForm($form, $form_state);
$form_state['values']['style_options']['formats'] = array_filter($form_state['values']['style_options']['formats']);
}
/**
* {@inheritdoc}
*/
public function render() {
$rows = array();
......@@ -72,4 +129,21 @@ public function render() {
return $this->serializer->serialize($rows, $this->displayHandler->getContentType());
}
/**
* Gets a list of all available formats that can be requested.
*
* This will return the configured formats, or all formats if none have been
* selected.
*
* @return array
* An array of formats.
*/
public function getFormats() {
if (!empty($this->options['formats'])) {
return $this->options['formats'];
}
return $this->formats;
}
}
......@@ -125,11 +125,49 @@ public function testSerializerResponses() {
$expected = $serializer->serialize($entities, 'hal_json');
$actual_json = $this->drupalGet('test/serialize/entity', array(), array('Accept: application/hal+json'));
$this->assertIdentical($actual_json, $expected, 'The expected HAL output was found.');
}
// Test that the default output will be JSON if html is requested.
$expected = $serializer->serialize($entities, 'json');
$actual = $this->drupalGet('test/serialize/entity');
$this->assertIdentical($actual, $expected, 'By default json output is returned.');
/**
* Tests the response format configuration.
*/
public function testReponseFormatConfiguration() {
$this->drupalLogin($this->adminUser);
$style_options = 'admin/structure/views/nojs/display/test_serializer_display_field/rest_export_1/style_options';
// Select only 'xml' as an accepted format.
$this->drupalPost($style_options, array('style_options[formats][xml]' => 'xml'), t('Apply'));
$this->drupalPost(NULL, array(), t('Save'));
// Should return a 406.
$this->drupalGet('test/serialize/field', array(), array('Accept: application/json'));
$this->assertResponse(406, 'A 406 response was returned when JSON was requested.');
// Should return a 200.
$this->drupalGet('test/serialize/field', array(), array('Accept: application/xml'));
$this->assertResponse(200, 'A 200 response was returned when XML was requested.');
// Add 'json' as an accepted format, so we have multiple.
$this->drupalPost($style_options, array('style_options[formats][json]' => 'json'), t('Apply'));
$this->drupalPost(NULL, array(), t('Save'));
// Should return a 200.
// @todo This should be fixed when we have better content negotiation.
$this->drupalGet('test/serialize/field', array(), array('Accept: */*'));
$this->assertResponse(200, 'A 200 response was returned when any format was requested.');
// Should return a 200. Emulates a sample Firefox header.
$this->drupalGet('test/serialize/field', array(), array('Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'));
$this->assertResponse(200, 'A 200 response was returned when a browser accept header was requested.');
// Should return a 200.
$this->drupalGet('test/serialize/field', array(), array('Accept: application/json'));
$this->assertResponse(200, 'A 200 response was returned when JSON was requested.');
// Should return a 200.
$this->drupalGet('test/serialize/field', array(), array('Accept: application/xml'));
$this->assertResponse(200, 'A 200 response was returned when XML was requested');
// Should return a 406.
$this->drupalGet('test/serialize/field', array(), array('Accept: application/html'));
$this->assertResponse(406, 'A 406 response was returned when HTML was requested.');
}
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment