You are here

public function RedirectPathTranslatorSubscriber::onPathTranslation in Decoupled Router 8

Same name and namespace in other branches
  1. 2.x src/EventSubscriber/RedirectPathTranslatorSubscriber.php \Drupal\decoupled_router\EventSubscriber\RedirectPathTranslatorSubscriber::onPathTranslation()

Processes a path translation request.

Overrides RouterPathTranslatorSubscriber::onPathTranslation

File

src/EventSubscriber/RedirectPathTranslatorSubscriber.php, line 29

Class

RedirectPathTranslatorSubscriber
Event subscriber that processes a path translation with the redirect info.

Namespace

Drupal\decoupled_router\EventSubscriber

Code

public function onPathTranslation(PathTranslatorEvent $event) {
  $response = $event
    ->getResponse();
  if (!$response instanceof CacheableJsonResponse) {
    $this->logger
      ->error('Unable to get the response object for the decoupled router event.');
    return;
  }
  if (!$this->moduleHandler
    ->moduleExists('redirect')) {
    return;
  }

  // Find the redirected path. Bear in mind that we need to go through several
  // redirection levels before handing off to the route translator.
  $entity_type_manager = $this->container
    ->get('entity_type.manager');
  $redirect_storage = $entity_type_manager
    ->getStorage('redirect');
  $destination = parse_url($event
    ->getPath(), PHP_URL_PATH);
  $original_query_string = parse_url($event
    ->getPath(), PHP_URL_QUERY);
  $traced_urls = [];
  $redirect = NULL;
  $redirects_trace = [];
  while (TRUE) {
    $destination = $this
      ->cleanSubdirInPath($destination, $event
      ->getRequest());

    // Find if there is a redirect for this path.
    $results = $redirect_storage
      ->getQuery()
      ->condition('redirect_source.path', ltrim($destination, '/'))
      ->execute();
    $rid = reset($results);
    if (!$rid) {
      break;
    }

    /** @var \Drupal\redirect\Entity\Redirect $redirect */
    $redirect = $redirect_storage
      ->load($rid);
    $response
      ->addCacheableDependency($redirect);
    $uri = $redirect
      ->get('redirect_redirect')->uri;
    $url = Url::fromUri($uri)
      ->toString(TRUE);
    $redirects_trace[] = [
      'from' => $this
        ->makeRedirectUrl($destination, $original_query_string),
      'to' => $this
        ->makeRedirectUrl($url
        ->getGeneratedUrl(), $original_query_string),
      'status' => $redirect
        ->getStatusCode(),
    ];
    $destination = $url
      ->getGeneratedUrl();

    // Detect infinite loops and break if there is one.
    $infinite_loop = in_array($destination, array_map(function (GeneratedUrl $url) {
      return $url
        ->getGeneratedUrl();
    }, $traced_urls));

    // Accumulate all the URLs we go through to add the necessary cacheability
    // metadata at the end.
    $traced_urls[] = $url;
    if ($infinite_loop) {
      break;
    }
  }
  if (!$redirect) {
    return;
  }

  // At this point we should be pointing to a system route or path alias.
  $event
    ->setPath($this
    ->makeRedirectUrl($destination, $original_query_string));

  // Now call the route level.
  parent::onPathTranslation($event);
  if (!$response
    ->isSuccessful()) {
    return;
  }

  // Set the content in the response.
  $content = Json::decode($response
    ->getContent());
  $response
    ->setData(array_merge($content, [
    'redirect' => $redirects_trace,
  ]));

  // If there is a response object, add the cacheability metadata necessary
  // for the traced URLs.
  array_walk($traced_urls, function ($traced_url) use ($response) {
    $response
      ->addCacheableDependency($traced_url);
  });
  $event
    ->stopPropagation();
}