You are here

public function Js::execute in JS Callback Handler 8.3

Executes the requested JS Callback.

Return value

\Drupal\js\JsResponse

File

src/Js.php, line 233

Class

Js
JS Callback Handler service.

Namespace

Drupal\js

Code

public function execute() {

  // Normalize "ajax_page_state" by manually setting a custom JS parameter.
  // This is required since AjaxBasePageNegotiator::applies() only checks for
  // "request" parameters (which does not include query parameters from GET).
  $this
    ->getRequest()->request
    ->set('ajax_page_state', $this
    ->getJsParameter('ajax_page_state'));

  // Retrieve any provided CSRF token.
  $this->token = $this
    ->getJsParameter('token');
  $callback = $this
    ->getCallback();
  $response = $this
    ->getResponse();
  $result = [];
  try {

    // Check callback's allowed methods.
    $allowed_methods = $callback
      ->getAllowedMethods();
    if (!in_array($this
      ->getRequest()
      ->getMethod(), $allowed_methods)) {
      throw new MethodNotAllowedHttpException($allowed_methods);
    }

    // Determine if a provided CSRF token should be validated.
    if ($callback
      ->csrfToken()) {

      // The current user must also not be anonymous as tokens would be the
      // same for all anonymous users. This is a security requirement.
      if (\Drupal::currentUser()
        ->isAnonymous()) {
        drupal_set_message($callback
          ->anonymousUserMessage(), 'error', FALSE);
        throw new AccessDeniedHttpException();
      }

      // Check for invalid token.
      if (!$this->token || !$this->tokenGenerator
        ->validate($this->token, 'js.callback:' . $callback
        ->getPluginId())) {
        drupal_set_message($callback
          ->invalidTokenMessage(), 'error', FALSE);
        throw new AccessDeniedHttpException();
      }
    }

    // Check callback access.
    $access = $callback
      ->call('access');
    if ($access instanceof AccessResultInterface && !$access
      ->isAllowed() || !$access) {
      throw new AccessDeniedHttpException();
    }

    // Invoke the callback, if it validated.
    if ($callback
      ->call('validate')) {
      $result = $callback
        ->call('execute');
    }
  } catch (AccessDeniedHttpException $e) {
    drupal_set_message($callback
      ->accessDeniedMessage(), 'error', FALSE);
    $response
      ->setStatusCode(403);
    $callback
      ->setTitle($this
      ->t('Access Denied'));
  } catch (MethodNotAllowedHttpException $e) {
    drupal_set_message($callback
      ->methodNotAllowedMessage(), 'error', FALSE);
    $response
      ->setStatusCode(405);
    $callback
      ->setTitle($this
      ->t('Method Not Allowed'));
  } catch (\Exception $e) {

    // Since "multiple catch types" is only supported in PHP 7.1 and higher,
    // there must be a global "catch" and their types checked here.
    // @see https://wiki.php.net/rfc/multiple-catch
    if ($e instanceof NotFoundHttpException || $e instanceof ResourceNotFoundException || $e instanceof MatchingRouteNotFoundException) {
      $response
        ->setStatusCode(404);
      $callback
        ->setTitle($this
        ->t('Page Not Found'));
    }

    // Otherwise, rethrow exception.
    throw $e;
  }

  // Deliver the result.
  return $this
    ->deliver($result);
}