Redirect404Subscriber.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. <?php
  2. namespace Drupal\redirect_404\EventSubscriber;
  3. use Drupal\Core\Config\ConfigFactoryInterface;
  4. use Drupal\Core\Language\LanguageManagerInterface;
  5. use Drupal\Core\Path\PathMatcherInterface;
  6. use Drupal\redirect_404\RedirectNotFoundStorageInterface;
  7. use Drupal\Core\Path\CurrentPathStack;
  8. use Symfony\Component\HttpFoundation\RequestStack;
  9. use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
  10. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  11. use Symfony\Component\HttpKernel\KernelEvents;
  12. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  13. /**
  14. * An EventSubscriber that listens to redirect 404 errors.
  15. */
  16. class Redirect404Subscriber implements EventSubscriberInterface {
  17. /**
  18. * The current path.
  19. *
  20. * @var \Drupal\Core\Path\CurrentPathStack
  21. */
  22. protected $currentPath;
  23. /**
  24. * The path matcher.
  25. *
  26. * @var \Drupal\Core\Path\PathMatcherInterface
  27. */
  28. protected $pathMatcher;
  29. /**
  30. * The request stack (get the URL argument(s) and combined it with the path).
  31. *
  32. * @var \Symfony\Component\HttpFoundation\RequestStack
  33. */
  34. protected $requestStack;
  35. /**
  36. * The language manager.
  37. *
  38. * @var \Drupal\Core\Language\LanguageManagerInterface
  39. */
  40. protected $languageManager;
  41. /**
  42. * The redirect storage.
  43. *
  44. * @var \Drupal\redirect_404\RedirectNotFoundStorageInterface
  45. */
  46. protected $redirectStorage;
  47. /**
  48. * The configuration factory.
  49. *
  50. * @var \Drupal\Core\Config\ConfigFactoryInterface
  51. */
  52. protected $config;
  53. /**
  54. * Constructs a new Redirect404Subscriber.
  55. *
  56. * @param \Drupal\Core\Path\CurrentPathStack $current_path
  57. * The current path.
  58. * @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
  59. * The path matcher service.
  60. * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
  61. * The request stack.
  62. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
  63. * The language manager.
  64. * @param \Drupal\redirect_404\RedirectNotFoundStorageInterface $redirect_storage
  65. * A redirect storage.
  66. * @param \Drupal\Core\Config\ConfigFactoryInterface $config
  67. * The configuration factory.
  68. */
  69. public function __construct(CurrentPathStack $current_path, PathMatcherInterface $path_matcher, RequestStack $request_stack, LanguageManagerInterface $language_manager, RedirectNotFoundStorageInterface $redirect_storage, ConfigFactoryInterface $config) {
  70. $this->currentPath = $current_path;
  71. $this->pathMatcher = $path_matcher;
  72. $this->requestStack = $request_stack;
  73. $this->languageManager = $language_manager;
  74. $this->redirectStorage = $redirect_storage;
  75. $this->config = $config->get('redirect_404.settings');
  76. }
  77. /**
  78. * {@inheritdoc}
  79. */
  80. public static function getSubscribedEvents() {
  81. $events[KernelEvents::EXCEPTION][] = 'onKernelException';
  82. return $events;
  83. }
  84. /**
  85. * Logs an exception of 404 Redirect errors.
  86. *
  87. * @param GetResponseForExceptionEvent $event
  88. * Is given by the event dispatcher.
  89. */
  90. public function onKernelException(GetResponseForExceptionEvent $event) {
  91. // Only log page not found (404) errors.
  92. if ($event->getException() instanceof NotFoundHttpException) {
  93. $path = $this->currentPath->getPath();
  94. // Ignore paths specified in the redirect settings.
  95. if ($pages = mb_strtolower($this->config->get('pages'))) {
  96. // Do not trim a trailing slash if that is the complete path.
  97. $path_to_match = $path === '/' ? $path : rtrim($path, '/');
  98. if ($this->pathMatcher->matchPath(mb_strtolower($path_to_match), $pages)) {
  99. return;
  100. }
  101. }
  102. // Allow to store paths with arguments.
  103. if ($query_string = $this->requestStack->getCurrentRequest()->getQueryString()) {
  104. $query_string = '?' . $query_string;
  105. }
  106. $path .= $query_string;
  107. $langcode = $this->languageManager->getCurrentLanguage()->getId();
  108. // Write record.
  109. $this->redirectStorage->logRequest($path, $langcode);
  110. }
  111. }
  112. }