From 41700e5027a7a1edff17d4f412a76202b4f1c19c Mon Sep 17 00:00:00 2001 From: redhead Date: Mon, 19 Jun 2017 09:17:33 +0300 Subject: [PATCH] Issue #2624972 by dstorozhuk, kalistos: No configuration possible in UI for 301, 303, etc. HTTP responses --- config/schema/page_manager.schema.yml | 3 + page_manager.install | 18 +++ .../HttpStatusCodeDisplayVariant.php | 154 ++++++++++++++++++++- 3 files changed, 174 insertions(+), 1 deletion(-) diff --git a/config/schema/page_manager.schema.yml b/config/schema/page_manager.schema.yml index 1fe3464..49e5cfc 100644 --- a/config/schema/page_manager.schema.yml +++ b/config/schema/page_manager.schema.yml @@ -139,3 +139,6 @@ display_variant.plugin.http_status_code: status_code: type: integer label: 'Status code' + redirect_location: + type: string + label: 'Redirect location' diff --git a/page_manager.install b/page_manager.install index 6180cf9..3073303 100644 --- a/page_manager.install +++ b/page_manager.install @@ -55,3 +55,21 @@ function page_manager_update_8002() { } } } + +/** + * Add "redirect_location" key to all "http_status_code" page variant according + * to an updated module schema. + */ +function page_manager_update_8401() { + $names = \Drupal::configFactory()->listAll('page_manager.page_variant'); + foreach ($names as $name) { + $config = \Drupal::configFactory()->getEditable($name); + if ($config->get('variant') === 'http_status_code') { + $variant_settings = $config->get('variant_settings'); + if (!key_exists('redirect_location', $variant_settings)) { + $config->set('variant_settings.redirect_location', ''); + $config->save(); + } + } + } +} diff --git a/src/Plugin/DisplayVariant/HttpStatusCodeDisplayVariant.php b/src/Plugin/DisplayVariant/HttpStatusCodeDisplayVariant.php index 47d0fa8..620a921 100644 --- a/src/Plugin/DisplayVariant/HttpStatusCodeDisplayVariant.php +++ b/src/Plugin/DisplayVariant/HttpStatusCodeDisplayVariant.php @@ -7,8 +7,11 @@ namespace Drupal\page_manager\Plugin\DisplayVariant; +use Drupal\Core\Display\ContextAwareVariantInterface; use Drupal\Core\Display\VariantBase; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Plugin\Context\Context; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\HttpException; @@ -20,7 +23,59 @@ use Symfony\Component\HttpKernel\Exception\HttpException; * admin_label = @Translation("HTTP status code") * ) */ -class HttpStatusCodeDisplayVariant extends VariantBase { +class HttpStatusCodeDisplayVariant extends VariantBase implements ContextAwareVariantInterface { + + /** + * @var \Drupal\Core\Path\AliasManagerInterface + */ + protected $aliasManager; + + /** + * An array of collected contexts. + * + * This is only used on runtime, and is not stored. + * + * @var \Drupal\Component\Plugin\Context\ContextInterface[] + */ + protected $contexts = []; + + /** + * List of codes with redirect action. + * + * @var array + */ + public static $redirectCodes = [301, 302, 303, 305, 307, 308]; + + /** + * Gets the contexts. + * + * @return \Drupal\Component\Plugin\Context\ContextInterface[] + * An array of set contexts, keyed by context name. + */ + public function getContexts() { + return $this->contexts; + } + + /** + * Sets the contexts. + * + * @param \Drupal\Component\Plugin\Context\ContextInterface[] $contexts + * An array of contexts, keyed by context name. + * + * @return $this + */ + public function setContexts(array $contexts) { + $this->contexts = $contexts; + return $this; + } + + /** + * {@inheritdoc} + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->aliasManager = \Drupal::service('path.alias_manager'); + } /** * {@inheritdoc} @@ -51,6 +106,25 @@ class HttpStatusCodeDisplayVariant extends VariantBase { '#default_value' => $this->configuration['status_code'], '#options' => $options, ]; + + $state_conditions = []; + foreach ($this::$redirectCodes as $code) { + $state_conditions[] = ['value' => $code]; + } + $form['redirect_location'] = [ + '#title' => $this->t('HTTP redirect location'), + '#type' => 'textfield', + '#default_value' => $this->configuration['redirect_location'], + '#states' => [ + 'visible' => [ + ':input[name="variant_settings[status_code]"]' => $state_conditions, + ], + 'required' => [ + ':input[name="variant_settings[status_code]"]' => $state_conditions, + ], + ], + ]; + return $form; } @@ -60,6 +134,7 @@ class HttpStatusCodeDisplayVariant extends VariantBase { public function defaultConfiguration() { $configuration = parent::defaultConfiguration(); $configuration['status_code'] = '404'; + $configuration['redirect_location'] = ''; return $configuration; } @@ -69,19 +144,96 @@ class HttpStatusCodeDisplayVariant extends VariantBase { public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { parent::submitConfigurationForm($form, $form_state); $this->configuration['status_code'] = $form_state->getValue('status_code'); + $this->configuration['redirect_location'] = $form_state->getValue('redirect_location'); } /** * {@inheritdoc} */ public function build() { + $status_code = $this->configuration['status_code']; if ($status_code == 200) { return []; } + elseif (in_array($status_code, $this::$redirectCodes, TRUE)) { + $redirect_location = $this->configuration['redirect_location']; + + $params = $this->getParameterNames($redirect_location); + + $contexts = $this->getContexts(); + foreach ($params as $param) { + if (!isset($contexts[$param])) { + continue; + } + + /** @var Context $context */ + $context = $contexts[$param]; + $value = $this->variableToString($context->getContextValue()); + if ($value === FALSE) { + continue; + } + + $redirect_location = str_replace('{' . $param . '}', $value, $redirect_location); + + if ($alias = $this->aliasManager->getAliasByPath($redirect_location)) { + $redirect_location = $alias; + } + } + + $response = new RedirectResponse($redirect_location, $status_code); + $response->send(); + exit; + } else { throw new HttpException($status_code); } } + /** + * Gets the names of all parameters for this page. + * + * @param string $path + * + * @return string[] + */ + public function getParameterNames($path) { + if (preg_match_all('|\{(\w+)\}|', $path, $matches)) { + return $matches[1]; + } + return []; + } + + /** + * Convert variable to string. + * + * @param $var + * + * @return bool|string + */ + private function variableToString($var) { + if (is_array($var)) { + $result = FALSE; + } + elseif (!is_object($var)) { + $result = settype($var, 'string') ? $var : FALSE; + } + elseif (is_object($var)) { + if (method_exists($var, '__toString')) { + $result = (string) $var; + } + elseif (method_exists($var, 'id')) { + $result = $var->id(); + } + else { + $result = FALSE; + } + } + else { + $result = FALSE; + } + + return $result; + } + } -- 2.10.1