*
* @var string
*/
- protected $mimeType;
+ protected $mimeType = 'application/json';
/**
* The renderer.
*/
protected $authenticationProviders;
+ /**
+ * The serialization format providers, keyed by format.
+ *
+ * @var string[]
+ */
+ protected $formatProviders;
+
/**
* Constructs a RestExport object.
*
* The renderer.
* @param string[] $authentication_providers
* The authentication providers, keyed by ID.
+ * @param string[] $serializer_format_providers
+ * The serialization format providers, keyed by format.
*/
- public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteProviderInterface $route_provider, StateInterface $state, RendererInterface $renderer, array $authentication_providers) {
+ public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteProviderInterface $route_provider, StateInterface $state, RendererInterface $renderer, array $authentication_providers, array $serializer_format_providers) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $route_provider, $state);
$this->renderer = $renderer;
$this->authenticationProviderIds = array_keys($authentication_providers);
// For BC reasons we keep around authenticationProviders as before.
$this->authenticationProviders = $authentication_providers;
+ $this->formatProviders = $serializer_format_providers;
}
/**
$container->get('router.route_provider'),
$container->get('state'),
$container->get('renderer'),
- $container->getParameter('authentication_providers')
-
+ $container->getParameter('authentication_providers'),
+ $container->getParameter('serializer.format_providers')
);
}
/**
public function initDisplay(ViewExecutable $view, array &$display, array &$options = NULL) {
parent::initDisplay($view, $display, $options);
+ // If the default 'json' format is not selected as a format option in the
+ // view display, fallback to the first format available for the default.
+ if (!empty($options['style']['options']['formats']) && !isset($options['style']['options']['formats'][$this->getContentType()])) {
+ $default_format = reset($options['style']['options']['formats']);
+ $this->setContentType($default_format);
+ }
+
+ // Only use the requested content type if it's not 'html'. This allows
+ // still falling back to the default for things like views preview.
$request_content_type = $this->view->getRequest()->getRequestFormat();
- // Only use the requested content type if it's not 'html'. If it is then
- // default to 'json' to aid debugging.
- // @todo Remove the need for this when we have better content negotiation.
- if ($request_content_type != 'html') {
+
+ if ($request_content_type !== 'html') {
$this->setContentType($request_content_type);
}
- // If the requested content type is 'html' and the default 'json' is not
- // selected as a format option in the view display, fallback to the first
- // format in the array.
- elseif (!empty($options['style']['options']['formats']) && !isset($options['style']['options']['formats'][$this->getContentType()])) {
- $this->setContentType(reset($options['style']['options']['formats']));
- }
- $this->setMimeType($this->view->getRequest()->getMimeType($this->contentType));
+ $this->setMimeType($this->view->getRequest()->getMimeType($this->getContentType()));
}
/**
if ($route = $collection->get("view.$view_id.$display_id")) {
$style_plugin = $this->getPlugin('style');
- // REST exports should only respond to get methods.
+
+ // REST exports should only respond to GET methods.
$route->setMethods(['GET']);
- // Format as a string using pipes as a delimiter.
- if ($formats = $style_plugin->getFormats()) {
- // Allow a REST Export View to be returned with an HTML-only accept
- // format. That allows browsers or other non-compliant systems to access
- // the view, as it is unlikely to have a conflicting HTML representation
- // anyway.
- $route->setRequirement('_format', implode('|', $formats + ['html']));
+ $formats = $style_plugin->getFormats();
+
+ // If there are no configured formats, add all formats that serialization
+ // is known to support.
+ if (!$formats) {
+ $formats = $this->getFormatOptions();
}
+
+ // Format as a string using pipes as a delimiter.
+ $route->setRequirement('_format', implode('|', $formats));
+
// Add authentication to the route if it was set. If no authentication was
// set, the default authentication will be used, which is cookie based by
// default.
$build['#suffix'] = '</pre>';
unset($build['#markup']);
}
- elseif ($this->view->getRequest()->getFormat($this->view->element['#content_type']) !== 'html') {
- // This display plugin is primarily for returning non-HTML formats.
- // However, we still invoke the renderer to collect cacheability metadata.
- // Because the renderer is designed for HTML rendering, it filters
- // #markup for XSS unless it is already known to be safe, but that filter
- // only works for HTML. Therefore, we mark the contents as safe to bypass
- // the filter. So long as we are returning this in a non-HTML response
- // (checked above), this is safe, because an XSS attack only works when
- // executed by an HTML agent.
+ else {
+ // This display plugin is for returning non-HTML formats. However, we
+ // still invoke the renderer to collect cacheability metadata. Because the
+ // renderer is designed for HTML rendering, it filters #markup for XSS
+ // unless it is already known to be safe, but that filter only works for
+ // HTML. Therefore, we mark the contents as safe to bypass the filter. So
+ // long as we are returning this in a non-HTML response,
+ // this is safe, because an XSS attack only works when executed by an HTML
+ // agent.
// @todo Decide how to support non-HTML in the render API in
// https://www.drupal.org/node/2501313.
$build['#markup'] = ViewsRenderPipelineMarkup::create($build['#markup']);
return $dependencies;
}
+ /**
+ * Returns an array of format options.
+ *
+ * @return string[]
+ * An array of format options. Both key and value are the same.
+ */
+ protected function getFormatOptions() {
+ $formats = array_keys($this->formatProviders);
+ return array_combine($formats, $formats);
+ }
+
}