You are here

class WebformExceptionHtmlSubscriber in Webform 6.x

Same name and namespace in other branches
  1. 8.5 src/EventSubscriber/WebformExceptionHtmlSubscriber.php \Drupal\webform\EventSubscriber\WebformExceptionHtmlSubscriber

Event subscriber to redirect to login form when webform settings instruct to.

Hierarchy

Expanded class hierarchy of WebformExceptionHtmlSubscriber

1 string reference to 'WebformExceptionHtmlSubscriber'
webform.services.yml in ./webform.services.yml
webform.services.yml
1 service uses WebformExceptionHtmlSubscriber
webform.exception_html_subscriber in ./webform.services.yml
Drupal\webform\EventSubscriber\WebformExceptionHtmlSubscriber

File

src/EventSubscriber/WebformExceptionHtmlSubscriber.php, line 31

Namespace

Drupal\webform\EventSubscriber
View source
class WebformExceptionHtmlSubscriber extends DefaultExceptionHtmlSubscriber {
  use StringTranslationTrait;

  /**
   * The current account.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $account;

  /**
   * The configuration object factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The renderer.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected $renderer;

  /**
   * The webform token manager.
   *
   * @var \Drupal\webform\WebformTokenManagerInterface
   */
  protected $tokenManager;

  /**
   * The messenger.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * Constructs a WebformExceptionHtmlSubscriber object.
   *
   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
   *   The HTTP kernel.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger service.
   * @param \Drupal\Core\Routing\RedirectDestinationInterface $redirect_destination
   *   The redirect destination service.
   * @param \Symfony\Component\Routing\Matcher\UrlMatcherInterface $access_unaware_router
   *   A router implementation which does not check access.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The current user.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The configuration object factory.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger.
   * @param \Drupal\webform\WebformTokenManagerInterface $token_manager
   *   The webform token manager.
   */
  public function __construct(HttpKernelInterface $http_kernel, LoggerInterface $logger, RedirectDestinationInterface $redirect_destination, UrlMatcherInterface $access_unaware_router, AccountInterface $account, ConfigFactoryInterface $config_factory, RendererInterface $renderer, MessengerInterface $messenger, WebformTokenManagerInterface $token_manager) {
    parent::__construct($http_kernel, $logger, $redirect_destination, $access_unaware_router);
    $this->account = $account;
    $this->configFactory = $config_factory;
    $this->renderer = $renderer;
    $this->messenger = $messenger;
    $this->tokenManager = $token_manager;
  }

  /**
   * {@inheritdoc}
   */
  protected static function getPriority() {

    // Execute before CustomPageExceptionHtmlSubscriber which is -50.
    // @see \Drupal\Core\EventSubscriber\CustomPageExceptionHtmlSubscriber::getPriority
    return -49;
  }

  /**
   * Handles a 403 error for HTML.
   *
   * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
   *   The event to process.
   */
  public function on403(GetResponseForExceptionEvent $event) {
    if ($event
      ->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) {
      return;
    }
    $this
      ->on403RedirectEntityAccess($event);
    $this
      ->on403RedirectPrivateFileAccess($event);
  }

  /**
   * Redirect to user login when access is denied to private webform file.
   *
   * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
   *   The event to process.
   *
   * @see webform_file_download()
   * @see \Drupal\webform\Plugin\WebformElement\WebformManagedFileBase::accessFileDownload
   */
  public function on403RedirectPrivateFileAccess(GetResponseForExceptionEvent $event) {
    $path = $event
      ->getRequest()
      ->getPathInfo();

    // Make sure the user is trying to access a private webform file upload.
    if (strpos($path, '/system/files/webform/') !== 0) {
      return;
    }

    // Make private webform file upload is not a temporary file.
    // @see \Drupal\webform\Plugin\WebformElement\WebformManagedFileBase::postSave
    if (strpos($path, '/_sid_/') !== FALSE) {
      return;
    }

    // Check that private file redirection is enabled.
    if (!$this->configFactory
      ->get('webform.settings')
      ->get('file.file_private_redirect')) {
      return;
    }
    $message = $this->configFactory
      ->get('webform.settings')
      ->get('file.file_private_redirect_message');
    $this
      ->redirectToLogin($event, $message);
  }

  /**
   * Redirect to user login when access is denied for webform or submission.
   *
   * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
   *   The event to process.
   */
  public function on403RedirectEntityAccess(GetResponseForExceptionEvent $event) {
    $url = Url::fromUserInput($event
      ->getRequest()
      ->getPathInfo());
    if (!$url) {
      return;
    }
    $route_parameters = $url
      ->isRouted() ? $url
      ->getRouteParameters() : [];
    if (empty($route_parameters['webform']) && empty($route_parameters['webform_submission'])) {
      return;
    }
    $config = $this->configFactory
      ->get('webform.settings');

    // If webform submission, handle login redirect.
    if (!empty($route_parameters['webform_submission'])) {
      $webform_submission = WebformSubmission::load($route_parameters['webform_submission']);
      $webform = $webform_submission
        ->getWebform();
      $submission_access_denied_message = $webform
        ->getSetting('submission_access_denied_message') ?: $config
        ->get('settings.default_submission_access_denied_message');
      switch ($webform
        ->getSetting('submission_access_denied')) {
        case WebformInterface::ACCESS_DENIED_LOGIN:
          $this
            ->redirectToLogin($event, $submission_access_denied_message, $webform_submission);
          break;
        case WebformInterface::ACCESS_DENIED_PAGE:

          // Must manually build access denied path so that base path is not
          // included.
          $this
            ->makeSubrequest($event, '/admin/structure/webform/manage/' . $webform
            ->id() . '/submission/' . $webform_submission
            ->id() . '/access-denied', Response::HTTP_FORBIDDEN);
          break;
        case WebformInterface::ACCESS_DENIED_DEFAULT:
        default:

          // Make the default 403 request so that we can add cacheable dependencies.
          $this
            ->makeSubrequest($event, $this
            ->getSystemSite403Path(), Response::HTTP_FORBIDDEN);
          break;
      }

      // Add cacheable dependencies.
      $response = $event
        ->getResponse();
      if ($response instanceof CacheableResponseInterface) {
        $response
          ->addCacheableDependency($webform);
        $response
          ->addCacheableDependency($webform_submission);
        $response
          ->addCacheableDependency($config);
      }
      return;
    }

    // If webform, handle access denied redirect or page.
    if (!empty($route_parameters['webform'])) {
      $webform = Webform::load($route_parameters['webform']);
      $webform_access_denied_message = $webform
        ->getSetting('form_access_denied_message') ?: $config
        ->get('settings.default_form_access_denied_message');
      switch ($webform
        ->getSetting('form_access_denied')) {
        case WebformInterface::ACCESS_DENIED_LOGIN:
          $this
            ->redirectToLogin($event, $webform_access_denied_message, $webform);
          break;
        case WebformInterface::ACCESS_DENIED_PAGE:

          // Must manually build access denied path so that base path is not
          // included.
          $this
            ->makeSubrequest($event, '/webform/' . $webform
            ->id() . '/access-denied', Response::HTTP_FORBIDDEN);
          break;
        case WebformInterface::ACCESS_DENIED_MESSAGE:

          // Display message.
          $this
            ->setMessage($webform_access_denied_message, $webform);

          // Make the default 403 request so that we can add cacheable dependencies.
          $this
            ->makeSubrequest($event, $this
            ->getSystemSite403Path(), Response::HTTP_FORBIDDEN);
          break;
        case WebformInterface::ACCESS_DENIED_DEFAULT:
        default:

          // Make the default 403 request so that we can add cacheable dependencies.
          $this
            ->makeSubrequest($event, $this
            ->getSystemSite403Path(), Response::HTTP_FORBIDDEN);
          break;
      }

      // Add cacheable dependencies.
      $response = $event
        ->getResponse();
      if ($response instanceof CacheableResponseInterface) {
        $response
          ->addCacheableDependency($webform);
        $response
          ->addCacheableDependency($config);
      }
      return;
    }
  }

  /**
   * {@inheritdoc}
   */
  protected function getHandledFormats() {
    return [
      'html',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function onException(GetResponseForExceptionEvent $event) {

    // Only handle 403 exception.
    // @see \Drupal\webform\EventSubscriber\WebformExceptionHtmlSubscriber::on403
    $exception = $event
      ->getException();
    if ($exception instanceof HttpExceptionInterface && $exception
      ->getStatusCode() === 403) {
      parent::onException($event);
    }
  }

  /**
   * Get 403 path from system.site config.
   *
   * @return string
   *   The custom 403 path or Drupal's default 403 path.
   */
  protected function getSystemSite403Path() {
    return $this->configFactory
      ->get('system.site')
      ->get('page.403') ?: '/system/403';
  }

  /**
   * Redirect to user login with destination and display custom message.
   *
   * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
   *   The event to process.
   * @param null|string $message
   *   (Optional) Message to be display on user login.
   * @param null|\Drupal\Core\Entity\EntityInterface $entity
   *   (Optional) Entity to be used when replacing tokens.
   */
  protected function redirectToLogin(GetResponseForExceptionEvent $event, $message = NULL, EntityInterface $entity = NULL) {

    // Display message.
    if ($message) {
      $this
        ->setMessage($message, $entity);
    }

    // Only redirect anonymous users.
    if ($this->account
      ->isAuthenticated()) {
      return;
    }
    $redirect_url = Url::fromRoute('user.login', [], [
      'absolute' => TRUE,
      'query' => $this->redirectDestination
        ->getAsArray(),
    ]);
    $event
      ->setResponse(new RedirectResponse($redirect_url
      ->toString()));
  }

  /**
   * Display custom message.
   *
   * @param null|string $message
   *   (Optional) Message to be display on user login.
   * @param null|\Drupal\Core\Entity\EntityInterface $entity
   *   (Optional) Entity to be used when replacing tokens.
   */
  protected function setMessage($message, EntityInterface $entity = NULL) {
    $message = $this->tokenManager
      ->replace($message, $entity);
    $build = WebformHtmlEditor::checkMarkup($message);
    $this->messenger
      ->addStatus($this->renderer
      ->renderPlain($build));
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DefaultExceptionHtmlSubscriber::$accessUnawareRouter protected property A router implementation which does not check access.
DefaultExceptionHtmlSubscriber::$httpKernel protected property The HTTP kernel.
DefaultExceptionHtmlSubscriber::$logger protected property The logger instance.
DefaultExceptionHtmlSubscriber::$redirectDestination protected property The redirect destination service.
DefaultExceptionHtmlSubscriber::makeSubrequest protected function Makes a subrequest to retrieve the default error page.
DefaultExceptionHtmlSubscriber::on401 public function Handles a 401 error for HTML.
DefaultExceptionHtmlSubscriber::on404 public function Handles a 404 error for HTML. 1
DefaultExceptionHtmlSubscriber::on4xx public function Handles a 4xx error for HTML.
HttpExceptionSubscriberBase::getSubscribedEvents public static function Registers the methods in this class that should be listeners.
StringTranslationTrait::$stringTranslation protected property The string translation service. 4
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
WebformExceptionHtmlSubscriber::$account protected property The current account.
WebformExceptionHtmlSubscriber::$configFactory protected property The configuration object factory.
WebformExceptionHtmlSubscriber::$messenger protected property The messenger.
WebformExceptionHtmlSubscriber::$renderer protected property The renderer.
WebformExceptionHtmlSubscriber::$tokenManager protected property The webform token manager.
WebformExceptionHtmlSubscriber::getHandledFormats protected function Specifies the request formats this subscriber will respond to. Overrides DefaultExceptionHtmlSubscriber::getHandledFormats
WebformExceptionHtmlSubscriber::getPriority protected static function Specifies the priority of all listeners in this class. Overrides DefaultExceptionHtmlSubscriber::getPriority
WebformExceptionHtmlSubscriber::getSystemSite403Path protected function Get 403 path from system.site config.
WebformExceptionHtmlSubscriber::on403 public function Handles a 403 error for HTML. Overrides DefaultExceptionHtmlSubscriber::on403
WebformExceptionHtmlSubscriber::on403RedirectEntityAccess public function Redirect to user login when access is denied for webform or submission.
WebformExceptionHtmlSubscriber::on403RedirectPrivateFileAccess public function Redirect to user login when access is denied to private webform file.
WebformExceptionHtmlSubscriber::onException public function Handles errors for this subscriber. Overrides HttpExceptionSubscriberBase::onException
WebformExceptionHtmlSubscriber::redirectToLogin protected function Redirect to user login with destination and display custom message.
WebformExceptionHtmlSubscriber::setMessage protected function Display custom message.
WebformExceptionHtmlSubscriber::__construct public function Constructs a WebformExceptionHtmlSubscriber object. Overrides DefaultExceptionHtmlSubscriber::__construct