You are here

ParamConversionEnhancer.php in Drupal 9

Same filename and directory in other branches
  1. 8 core/lib/Drupal/Core/Routing/Enhancer/ParamConversionEnhancer.php

File

core/lib/Drupal/Core/Routing/Enhancer/ParamConversionEnhancer.php
View source
<?php

namespace Drupal\Core\Routing\Enhancer;

use Drupal\Core\ParamConverter\ParamConverterManagerInterface;
use Drupal\Core\ParamConverter\ParamNotConvertedException;
use Drupal\Core\Routing\EnhancerInterface;
use Drupal\Core\Routing\RouteObjectInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Provides a route enhancer that handles parameter conversion.
 */
class ParamConversionEnhancer implements EnhancerInterface, EventSubscriberInterface {

  /**
   * The parameter conversion manager.
   *
   * @var \Drupal\Core\ParamConverter\ParamConverterManagerInterface
   */
  protected $paramConverterManager;

  /**
   * Constructs a new ParamConversionEnhancer.
   *
   * @param \Drupal\Core\ParamConverter\ParamConverterManagerInterface $param_converter_manager
   *   The parameter conversion manager.
   */
  public function __construct(ParamConverterManagerInterface $param_converter_manager) {
    $this->paramConverterManager = $param_converter_manager;
  }

  /**
   * {@inheritdoc}
   */
  public function enhance(array $defaults, Request $request) {

    // Just run the parameter conversion once per request.
    if (!isset($defaults['_raw_variables'])) {
      $defaults['_raw_variables'] = $this
        ->copyRawVariables($defaults);
      $defaults = $this->paramConverterManager
        ->convert($defaults);
    }
    return $defaults;
  }

  /**
   * Store a backup of the raw values that corresponding to the route pattern.
   *
   * @param array $defaults
   *   The route defaults array.
   *
   * @return \Symfony\Component\HttpFoundation\ParameterBag
   */
  protected function copyRawVariables(array $defaults) {

    /** @var \Symfony\Component\Routing\Route $route */
    $route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
    $variables = array_flip($route
      ->compile()
      ->getVariables());

    // Foreach will copy the values from the array it iterates. Even if they
    // are references, use it to break them. This avoids any scenarios where raw
    // variables also get replaced with converted values.
    $raw_variables = [];
    foreach (array_intersect_key($defaults, $variables) as $key => $value) {
      $raw_variables[$key] = $value;
    }
    return new ParameterBag($raw_variables);
  }

  /**
   * Catches failed parameter conversions and throw a 404 instead.
   *
   * @param \Symfony\Component\HttpKernel\Event\ExceptionEvent $event
   */
  public function onException(ExceptionEvent $event) {
    $exception = $event
      ->getThrowable();
    if ($exception instanceof ParamNotConvertedException) {
      $event
        ->setThrowable(new NotFoundHttpException($exception
        ->getMessage(), $exception));
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[KernelEvents::EXCEPTION][] = [
      'onException',
      75,
    ];
    return $events;
  }

}

Classes

Namesort descending Description
ParamConversionEnhancer Provides a route enhancer that handles parameter conversion.