Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\node\EventSubscriber;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
|
Chris@0
|
6 use Drupal\Core\Language\LanguageManagerInterface;
|
Chris@0
|
7 use Drupal\Core\ParamConverter\ParamNotConvertedException;
|
Chris@0
|
8 use Drupal\Core\Routing\UrlGeneratorInterface;
|
Chris@0
|
9 use Drupal\Core\State\StateInterface;
|
Chris@0
|
10 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
Chris@0
|
11 use Symfony\Component\HttpFoundation\RedirectResponse;
|
Chris@0
|
12 use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
Chris@0
|
13 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
Chris@0
|
14 use Symfony\Component\HttpKernel\KernelEvents;
|
Chris@0
|
15
|
Chris@0
|
16 /**
|
Chris@0
|
17 * Redirect node translations that have been consolidated by migration.
|
Chris@0
|
18 *
|
Chris@0
|
19 * If we migrated node translations from Drupal 6 or 7, these nodes are now
|
Chris@0
|
20 * combined with their source language node. Since there still might be
|
Chris@0
|
21 * references to the URLs of these now consolidated nodes, this service catches
|
Chris@0
|
22 * the 404s and try to redirect them to the right node in the right language.
|
Chris@0
|
23 *
|
Chris@0
|
24 * The mapping of the old nids to the new ones is made by the
|
Chris@0
|
25 * NodeTranslationMigrateSubscriber class during the migration and is stored
|
Chris@0
|
26 * in the "node_translation_redirect" key/value collection.
|
Chris@0
|
27 *
|
Chris@0
|
28 * @see \Drupal\node\NodeServiceProvider
|
Chris@0
|
29 * @see \Drupal\node\EventSubscriber\NodeTranslationMigrateSubscriber
|
Chris@0
|
30 */
|
Chris@0
|
31 class NodeTranslationExceptionSubscriber implements EventSubscriberInterface {
|
Chris@0
|
32
|
Chris@0
|
33 /**
|
Chris@0
|
34 * The key value factory.
|
Chris@0
|
35 *
|
Chris@0
|
36 * @var \Drupal\Core\KeyValueStore\KeyValueFactoryInterface
|
Chris@0
|
37 */
|
Chris@0
|
38 protected $keyValue;
|
Chris@0
|
39
|
Chris@0
|
40 /**
|
Chris@0
|
41 * The language manager.
|
Chris@0
|
42 *
|
Chris@0
|
43 * @var \Drupal\Core\Language\LanguageManagerInterface
|
Chris@0
|
44 */
|
Chris@0
|
45 protected $languageManager;
|
Chris@0
|
46
|
Chris@0
|
47 /**
|
Chris@0
|
48 * The URL generator.
|
Chris@0
|
49 *
|
Chris@0
|
50 * @var \Drupal\Core\Routing\UrlGeneratorInterface
|
Chris@0
|
51 */
|
Chris@0
|
52 protected $urlGenerator;
|
Chris@0
|
53
|
Chris@0
|
54 /**
|
Chris@0
|
55 * The state service.
|
Chris@0
|
56 *
|
Chris@0
|
57 * @var \Drupal\Core\State\StateInterface
|
Chris@0
|
58 */
|
Chris@0
|
59 protected $state;
|
Chris@0
|
60
|
Chris@0
|
61 /**
|
Chris@0
|
62 * Constructs the NodeTranslationExceptionSubscriber.
|
Chris@0
|
63 *
|
Chris@0
|
64 * @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value
|
Chris@0
|
65 * The key value factory.
|
Chris@0
|
66 * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
Chris@0
|
67 * The language manager.
|
Chris@0
|
68 * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
|
Chris@0
|
69 * The URL generator.
|
Chris@0
|
70 * @param \Drupal\Core\State\StateInterface $state
|
Chris@0
|
71 * The state service.
|
Chris@0
|
72 */
|
Chris@0
|
73 public function __construct(KeyValueFactoryInterface $key_value, LanguageManagerInterface $language_manager, UrlGeneratorInterface $url_generator, StateInterface $state) {
|
Chris@0
|
74 $this->keyValue = $key_value;
|
Chris@0
|
75 $this->languageManager = $language_manager;
|
Chris@0
|
76 $this->urlGenerator = $url_generator;
|
Chris@0
|
77 $this->state = $state;
|
Chris@0
|
78 }
|
Chris@0
|
79
|
Chris@0
|
80 /**
|
Chris@0
|
81 * Redirects not found node translations using the key value collection.
|
Chris@0
|
82 *
|
Chris@0
|
83 * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
|
Chris@0
|
84 * The exception event.
|
Chris@0
|
85 */
|
Chris@0
|
86 public function onException(GetResponseForExceptionEvent $event) {
|
Chris@0
|
87 $exception = $event->getException();
|
Chris@0
|
88
|
Chris@0
|
89 // If this is not a 404, we don't need to check for a redirection.
|
Chris@0
|
90 if (!($exception instanceof NotFoundHttpException)) {
|
Chris@0
|
91 return;
|
Chris@0
|
92 }
|
Chris@0
|
93
|
Chris@0
|
94 $previous_exception = $exception->getPrevious();
|
Chris@0
|
95 if ($previous_exception instanceof ParamNotConvertedException) {
|
Chris@0
|
96 $route_name = $previous_exception->getRouteName();
|
Chris@0
|
97 $parameters = $previous_exception->getRawParameters();
|
Chris@0
|
98 if ($route_name === 'entity.node.canonical' && isset($parameters['node'])) {
|
Chris@0
|
99 // If the node_translation_redirect state is not set, we don't need to check
|
Chris@0
|
100 // for a redirection.
|
Chris@0
|
101 if (!$this->state->get('node_translation_redirect')) {
|
Chris@0
|
102 return;
|
Chris@0
|
103 }
|
Chris@0
|
104 $old_nid = $parameters['node'];
|
Chris@0
|
105 $collection = $this->keyValue->get('node_translation_redirect');
|
Chris@0
|
106 if ($old_nid && $value = $collection->get($old_nid)) {
|
Chris@0
|
107 list($nid, $langcode) = $value;
|
Chris@0
|
108 $language = $this->languageManager->getLanguage($langcode);
|
Chris@0
|
109 $url = $this->urlGenerator->generateFromRoute('entity.node.canonical', ['node' => $nid], ['language' => $language]);
|
Chris@0
|
110 $response = new RedirectResponse($url, 301);
|
Chris@0
|
111 $event->setResponse($response);
|
Chris@0
|
112 }
|
Chris@0
|
113 }
|
Chris@0
|
114 }
|
Chris@0
|
115 }
|
Chris@0
|
116
|
Chris@0
|
117 /**
|
Chris@0
|
118 * {@inheritdoc}
|
Chris@0
|
119 */
|
Chris@0
|
120 public static function getSubscribedEvents() {
|
Chris@0
|
121 $events = [];
|
Chris@0
|
122
|
Chris@0
|
123 $events[KernelEvents::EXCEPTION] = ['onException'];
|
Chris@0
|
124
|
Chris@0
|
125 return $events;
|
Chris@0
|
126 }
|
Chris@0
|
127
|
Chris@0
|
128 }
|