b4d335656915a8b23861b31d88a5d13bf39804bc
[yaffs-website] / web / core / modules / config_translation / src / Controller / ConfigTranslationController.php
1 <?php
2
3 namespace Drupal\config_translation\Controller;
4
5 use Drupal\config_translation\ConfigMapperManagerInterface;
6 use Drupal\config_translation\Exception\ConfigMapperLanguageException;
7 use Drupal\Core\Access\AccessManagerInterface;
8 use Drupal\Core\Controller\ControllerBase;
9 use Drupal\Core\Language\Language;
10 use Drupal\Core\Language\LanguageInterface;
11 use Drupal\Core\Language\LanguageManagerInterface;
12 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
13 use Drupal\Core\Render\RendererInterface;
14 use Drupal\Core\Routing\RouteMatch;
15 use Drupal\Core\Routing\RouteMatchInterface;
16 use Drupal\Core\Session\AccountInterface;
17 use Drupal\Core\Url;
18 use Symfony\Component\DependencyInjection\ContainerInterface;
19 use Symfony\Component\HttpFoundation\Request;
20 use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
21
22 /**
23  * Provides page callbacks for the configuration translation interface.
24  */
25 class ConfigTranslationController extends ControllerBase {
26
27   /**
28    * The configuration mapper manager.
29    *
30    * @var \Drupal\config_translation\ConfigMapperManagerInterface
31    */
32   protected $configMapperManager;
33
34   /**
35    * The menu link access service.
36    *
37    * @var \Drupal\Core\Access\AccessManagerInterface
38    */
39   protected $accessManager;
40
41   /**
42    * The dynamic router service.
43    *
44    * @var \Symfony\Component\Routing\Matcher\RequestMatcherInterface
45    */
46   protected $router;
47
48   /**
49    * The path processor service.
50    *
51    * @var \Drupal\Core\PathProcessor\InboundPathProcessorInterface
52    */
53   protected $pathProcessor;
54
55   /**
56    * The current user.
57    *
58    * @var \Drupal\Core\Session\AccountInterface
59    */
60   protected $account;
61
62   /**
63    * The language manager.
64    *
65    * @var \Drupal\Core\Language\LanguageManagerInterface
66    */
67   protected $languageManager;
68
69   /**
70    * The renderer.
71    *
72    * @var \Drupal\Core\Render\RendererInterface
73    */
74   protected $renderer;
75
76   /**
77    * Constructs a ConfigTranslationController.
78    *
79    * @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager
80    *   The configuration mapper manager.
81    * @param \Drupal\Core\Access\AccessManagerInterface $access_manager
82    *   The menu link access service.
83    * @param \Symfony\Component\Routing\Matcher\RequestMatcherInterface $router
84    *   The dynamic router service.
85    * @param \Drupal\Core\PathProcessor\InboundPathProcessorInterface $path_processor
86    *   The inbound path processor.
87    * @param \Drupal\Core\Session\AccountInterface $account
88    *   The current user.
89    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
90    *   The language manager.
91    * @param \Drupal\Core\Render\RendererInterface $renderer
92    *   The renderer.
93    */
94   public function __construct(ConfigMapperManagerInterface $config_mapper_manager, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, AccountInterface $account, LanguageManagerInterface $language_manager, RendererInterface $renderer) {
95     $this->configMapperManager = $config_mapper_manager;
96     $this->accessManager = $access_manager;
97     $this->router = $router;
98     $this->pathProcessor = $path_processor;
99     $this->account = $account;
100     $this->languageManager = $language_manager;
101     $this->renderer = $renderer;
102   }
103
104   /**
105    * {@inheritdoc}
106    */
107   public static function create(ContainerInterface $container) {
108     return new static(
109       $container->get('plugin.manager.config_translation.mapper'),
110       $container->get('access_manager'),
111       $container->get('router'),
112       $container->get('path_processor_manager'),
113       $container->get('current_user'),
114       $container->get('language_manager'),
115       $container->get('renderer')
116     );
117   }
118
119   /**
120    * Language translations overview page for a configuration name.
121    *
122    * @param \Symfony\Component\HttpFoundation\Request $request
123    *   Page request object.
124    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
125    *   The route match.
126    * @param string $plugin_id
127    *   The plugin ID of the mapper.
128    *
129    * @return array
130    *   Page render array.
131    */
132   public function itemPage(Request $request, RouteMatchInterface $route_match, $plugin_id) {
133     /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
134     $mapper = $this->configMapperManager->createInstance($plugin_id);
135     $mapper->populateFromRouteMatch($route_match);
136
137     $page = [];
138     $page['#title'] = $this->t('Translations for %label', ['%label' => $mapper->getTitle()]);
139
140     $languages = $this->languageManager->getLanguages();
141     if (count($languages) == 1) {
142       $this->messenger()->addWarning($this->t('In order to translate configuration, the website must have at least two <a href=":url">languages</a>.', [':url' => $this->url('entity.configurable_language.collection')]));
143     }
144
145     try {
146       $original_langcode = $mapper->getLangcode();
147       $operations_access = TRUE;
148     }
149     catch (ConfigMapperLanguageException $exception) {
150       $items = [];
151       foreach ($mapper->getConfigNames() as $config_name) {
152         $langcode = $mapper->getLangcodeFromConfig($config_name);
153         $items[] = $this->t('@name: @langcode', [
154           '@name' => $config_name,
155           '@langcode'  => $langcode,
156         ]);
157       }
158       $message = [
159         'message' => ['#markup' => $this->t('The configuration objects have different language codes so they cannot be translated:')],
160         'items' => [
161           '#theme' => 'item_list',
162           '#items' => $items,
163         ],
164       ];
165       $this->messenger()->addWarning($this->renderer->renderPlain($message));
166
167       $original_langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
168       $operations_access = FALSE;
169     }
170
171     if (!isset($languages[$original_langcode])) {
172       // If the language is not configured on the site, create a dummy language
173       // object for this listing only to ensure the user gets useful info.
174       $language_name = $this->languageManager->getLanguageName($original_langcode);
175       $languages[$original_langcode] = new Language(['id' => $original_langcode, 'name' => $language_name]);
176     }
177
178     // We create a fake request object to pass into
179     // ConfigMapperInterface::populateFromRouteMatch() for the different languages.
180     // Creating a separate request for each language and route is neither easily
181     // possible nor performant.
182     $fake_request = $request->duplicate();
183
184     $page['languages'] = [
185       '#type' => 'table',
186       '#header' => [$this->t('Language'), $this->t('Operations')],
187     ];
188     foreach ($languages as $language) {
189       $langcode = $language->getId();
190
191       // This is needed because
192       // ConfigMapperInterface::getAddRouteParameters(), for example,
193       // needs to return the correct language code for each table row.
194       $fake_route_match = RouteMatch::createFromRequest($fake_request);
195       $mapper->populateFromRouteMatch($fake_route_match);
196       $mapper->setLangcode($langcode);
197
198       // Prepare the language name and the operations depending on whether this
199       // is the original language or not.
200       if ($langcode == $original_langcode) {
201         $language_name = '<strong>' . $this->t('@language (original)', ['@language' => $language->getName()]) . '</strong>';
202
203         // Check access for the path/route for editing, so we can decide to
204         // include a link to edit or not.
205         $edit_access = $this->accessManager->checkNamedRoute($mapper->getBaseRouteName(), $route_match->getRawParameters()->all(), $this->account);
206
207         // Build list of operations.
208         $operations = [];
209         if ($edit_access) {
210           $operations['edit'] = [
211             'title' => $this->t('Edit'),
212             'url' => Url::fromRoute($mapper->getBaseRouteName(), $mapper->getBaseRouteParameters(), ['query' => ['destination' => $mapper->getOverviewPath()]]),
213           ];
214         }
215       }
216       else {
217         $language_name = $language->getName();
218
219         $operations = [];
220         // If no translation exists for this language, link to add one.
221         if (!$mapper->hasTranslation($language)) {
222           $operations['add'] = [
223             'title' => $this->t('Add'),
224             'url' => Url::fromRoute($mapper->getAddRouteName(), $mapper->getAddRouteParameters()),
225           ];
226         }
227         else {
228           // Otherwise, link to edit the existing translation.
229           $operations['edit'] = [
230             'title' => $this->t('Edit'),
231             'url' => Url::fromRoute($mapper->getEditRouteName(), $mapper->getEditRouteParameters()),
232           ];
233
234           $operations['delete'] = [
235             'title' => $this->t('Delete'),
236             'url' => Url::fromRoute($mapper->getDeleteRouteName(), $mapper->getDeleteRouteParameters()),
237           ];
238         }
239       }
240
241       $page['languages'][$langcode]['language'] = [
242         '#markup' => $language_name,
243       ];
244
245       $page['languages'][$langcode]['operations'] = [
246         '#type' => 'operations',
247         '#links' => $operations,
248         // Even if the mapper contains multiple language codes, the source
249         // configuration can still be edited.
250         '#access' => ($langcode == $original_langcode) || $operations_access,
251       ];
252     }
253     return $page;
254   }
255
256 }