‪TYPO3CMS  9.5
LanguageMenuProcessor.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
3 
5 
6 /*
7  * This file is part of the TYPO3 CMS project.
8  *
9  * It is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU General Public License, either version 2
11  * of the License, or any later version.
12  *
13  * For the full copyright and license information, please read the
14  * LICENSE.txt file that was distributed with this source code.
15  *
16  * The TYPO3 project - inspiring people to share!
17  */
18 
27 
45 {
46  protected const ‪LINK_PLACEHOLDER = '###LINKPLACEHOLDER###';
47 
53  public ‪$cObj;
54 
61 
68  protected ‪$allowedConfigurationKeys = [
69  'if',
70  'if.',
71  'languages',
72  'languages.',
73  'as',
74  'addQueryString',
75  'addQueryString.'
76  ];
77 
85  'languages',
86  'languages.',
87  'as'
88  ];
89 
93  protected ‪$menuConfig = [
94  'special' => 'language',
95  'addQueryString' => 1,
96  'addQueryString.' => [
97  'method' => 'GET'
98  ],
99  'wrap' => '[|]'
100  ];
101 
105  protected ‪$menuLevelConfig = [
106  'doNotLinkIt' => '1',
107  'wrapItemAndSub' => '{|}, |*| {|}, |*| {|}',
108  'stdWrap.' => [
109  'cObject' => 'COA',
110  'cObject.' => [
111  '1' => 'LOAD_REGISTER',
112  '1.' => [
113  'languageId.' => [
114  'cObject' => 'TEXT',
115  'cObject.' => [
116  'value.' => [
117  'data' => 'register:languages_HMENU'
118  ],
119  'listNum.' => [
120  'stdWrap.' => [
121  'data' => 'register:count_HMENU_MENUOBJ',
122  'wrap' => '|-1'
123  ],
124  'splitChar' => ','
125  ]
126  ]
127  ]
128  ],
129  '10' => 'TEXT',
130  '10.' => [
131  'stdWrap.' => [
132  'data' => 'register:languageId'
133  ],
134  'wrap' => '"languageId":|'
135  ],
136  '11' => 'USER',
137  '11.' => [
138  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
139  'language.' => [
140  'data' => 'register:languageId'
141  ],
142  'field' => 'locale',
143  'stdWrap.' => [
144  'wrap' => ',"locale":|'
145  ]
146  ],
147  '20' => 'USER',
148  '20.' => [
149  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
150  'language.' => [
151  'data' => 'register:languageId'
152  ],
153  'field' => 'title',
154  'stdWrap.' => [
155  'wrap' => ',"title":|'
156  ]
157  ],
158  '21' => 'USER',
159  '21.' => [
160  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
161  'language.' => [
162  'data' => 'register:languageId'
163  ],
164  'field' => 'navigationTitle',
165  'stdWrap.' => [
166  'wrap' => ',"navigationTitle":|'
167  ]
168  ],
169  '22' => 'USER',
170  '22.' => [
171  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
172  'language.' => [
173  'data' => 'register:languageId'
174  ],
175  'field' => 'twoLetterIsoCode',
176  'stdWrap.' => [
177  'wrap' => ',"twoLetterIsoCode":|'
178  ]
179  ],
180  '23' => 'USER',
181  '23.' => [
182  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
183  'language.' => [
184  'data' => 'register:languageId'
185  ],
186  'field' => 'hreflang',
187  'stdWrap.' => [
188  'wrap' => ',"hreflang":|'
189  ]
190  ],
191  '24' => 'USER',
192  '24.' => [
193  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
194  'language.' => [
195  'data' => 'register:languageId'
196  ],
197  'field' => 'direction',
198  'stdWrap.' => [
199  'wrap' => ',"direction":|'
200  ]
201  ],
202  '90' => 'TEXT',
203  '90.' => [
204  'value' => ‪self::LINK_PLACEHOLDER,
205  'wrap' => ',"link":|',
206  ],
207  '91' => 'TEXT',
208  '91.' => [
209  'value' => '0',
210  'wrap' => ',"active":|'
211  ],
212  '92' => 'TEXT',
213  '92.' => [
214  'value' => '0',
215  'wrap' => ',"current":|'
216  ],
217  '93' => 'TEXT',
218  '93.' => [
219  'value' => '1',
220  'wrap' => ',"available":|'
221  ],
222  '99' => 'RESTORE_REGISTER'
223  ]
224  ]
225  ];
226 
230  protected ‪$menuDefaults = [
231  'as' => 'languagemenu'
232  ];
233 
237  protected ‪$menuTargetVariableName;
238 
242  protected ‪$contentDataProcessor;
243 
247  public function ‪__construct()
248  {
249  $this->contentDataProcessor = GeneralUtility::makeInstance(ContentDataProcessor::class);
250  }
251 
258  protected function ‪getConfigurationValue(string $key): string
259  {
260  return $this->cObj->stdWrapValue($key, $this->processorConfiguration, $this->menuDefaults[$key]);
261  }
262 
266  protected function ‪getTypoScriptFrontendController(): TypoScriptFrontendController
267  {
268  return ‪$GLOBALS['TSFE'];
269  }
270 
277  protected function ‪getCurrentSite(): ‪SiteInterface
278  {
279  $matcher = GeneralUtility::makeInstance(SiteMatcher::class);
280  return $matcher->matchByPageId((int)$this->‪getTypoScriptFrontendController()->id);
281  }
282 
289  protected function ‪jsonEncode($value): string
290  {
291  return json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE);
292  }
293 
297  protected function ‪validateConfiguration()
298  {
299  $invalidArguments = [];
300  foreach ($this->processorConfiguration as $key => $value) {
301  if (!in_array($key, $this->allowedConfigurationKeys)) {
302  $invalidArguments[str_replace('.', '', $key)] = $key;
303  }
304  }
305  if (!empty($invalidArguments)) {
306  throw new \InvalidArgumentException('LanguageMenuProcessor configuration contains invalid arguments: ' . implode(', ', $invalidArguments), 1522959188);
307  }
308  }
309 
313  protected function ‪prepareConfiguration(): void
314  {
315  $this->menuConfig = array_merge($this->menuConfig, $this->processorConfiguration);
316 
317  // Process languages
318  if (empty($this->menuConfig['languages']) && empty($this->menuConfig['languages.'])) {
319  $this->menuConfig['special.']['value'] = 'auto';
320  } elseif (!empty($this->menuConfig['languages.'])) {
321  $this->menuConfig['special.']['value'] = $this->cObj->stdWrap($this->menuConfig['languages'], $this->menuConfig['languages.']);
322  } else {
323  $this->menuConfig['special.']['value'] = $this->menuConfig['languages'];
324  }
325 
326  // Filter configuration
327  foreach ($this->menuConfig as $key => $value) {
328  if (in_array($key, $this->removeConfigurationKeysForHmenu, true)) {
329  unset($this->menuConfig[$key]);
330  }
331  }
332 
334  (int)$this->‪getTypoScriptFrontendController()->id,
335  (array)‪$GLOBALS['TYPO3_CONF_VARS']['FE']['additionalCanonicalizedUrlParameters']
336  );
337 
338  $this->menuConfig['addQueryString.']['exclude'] = implode(
339  ',',
340  array_merge(
341  GeneralUtility::trimExplode(',', $this->menuConfig['addQueryString.']['exclude'] ?? '', true),
342  $paramsToExclude
343  )
344  );
345  }
346 
350  protected function ‪buildConfiguration(): void
351  {
352  $this->menuConfig['1'] = 'TMENU';
353  $this->menuConfig['1.']['IProcFunc'] = LanguageMenuProcessor::class . '->replacePlaceholderInRenderedMenuItem';
354  $this->menuConfig['1.']['NO'] = '1';
355  $this->menuConfig['1.']['NO.'] = ‪$this->menuLevelConfig;
356  $this->menuConfig['1.']['ACT'] = $this->menuConfig['1.']['NO'];
357  $this->menuConfig['1.']['ACT.'] = $this->menuConfig['1.']['NO.'];
358  $this->menuConfig['1.']['ACT.']['stdWrap.']['cObject.']['91.']['value'] = '1';
359  $this->menuConfig['1.']['CUR'] = $this->menuConfig['1.']['ACT'];
360  $this->menuConfig['1.']['CUR.'] = $this->menuConfig['1.']['ACT.'];
361  $this->menuConfig['1.']['CUR.']['stdWrap.']['cObject.']['92.']['value'] = '1';
362  $this->menuConfig['1.']['USERDEF1'] = $this->menuConfig['1.']['NO'];
363  $this->menuConfig['1.']['USERDEF1.'] = $this->menuConfig['1.']['NO.'];
364  $this->menuConfig['1.']['USERDEF1.']['stdWrap.']['cObject.']['93.']['value'] = '0';
365  $this->menuConfig['1.']['USERDEF2'] = $this->menuConfig['1.']['ACT'];
366  $this->menuConfig['1.']['USERDEF2.'] = $this->menuConfig['1.']['ACT.'];
367  $this->menuConfig['1.']['USERDEF2.']['stdWrap.']['cObject.']['93.']['value'] = '0';
368  }
369 
373  protected function ‪validateAndBuildConfiguration(): void
374  {
375  // Validate Configuration
376  $this->‪validateConfiguration();
377 
378  // Build Configuration
379  $this->‪prepareConfiguration();
380  $this->‪buildConfiguration();
381  }
382 
390  public function ‪process(‪ContentObjectRenderer ‪$cObj, array $contentObjectConfiguration, array ‪$processorConfiguration, array $processedData): array
391  {
392  $this->cObj = ‪$cObj;
393  $this->processorConfiguration = ‪$processorConfiguration;
394 
395  // Get Configuration
396  $this->menuTargetVariableName = $this->‪getConfigurationValue('as');
397 
398  // Validate and Build Configuration
400 
401  // Process Configuration
402  $menuContentObject = ‪$cObj->‪getContentObject('HMENU');
403  $renderedMenu = $menuContentObject->‪render($this->menuConfig);
404  if ($renderedMenu) {
405  // Process menu
406  $menu = json_decode($renderedMenu, true);
407  $processedMenu = [];
408 
409  foreach ($menu as $key => $language) {
410  $processedMenu[$key] = $language;
411  }
412 
413  $processedData[‪$this->menuTargetVariableName] = $processedMenu;
414  }
415 
416  return $processedData;
417  }
418 
425  public function ‪replacePlaceholderInRenderedMenuItem(array $menuItem): array
426  {
427  $link = $this->‪jsonEncode($menuItem['linkHREF']['HREF']);
428 
429  $menuItem['parts']['title'] = str_replace(self::LINK_PLACEHOLDER, $link, $menuItem['parts']['title']);
430 
431  return $menuItem;
432  }
433 
443  public function ‪getFieldAsJson(string $content, array $conf): string
444  {
445  // Support of stdWrap for parameters
446  if (isset($conf['language.'])) {
447  $conf['language'] = $this->cObj->stdWrap($conf['language'], $conf['language.']);
448  unset($conf['language.']);
449  }
450  if (isset($conf['field.'])) {
451  $conf['field'] = $this->cObj->stdWrap($conf['field'], $conf['field.']);
452  unset($conf['field.']);
453  }
454 
455  // Check required fields
456  if ($conf['language'] === '') {
457  throw new \InvalidArgumentException('Argument \'language\' must be supplied.', 1522959186);
458  }
459  if ($conf['field'] === '') {
460  throw new \InvalidArgumentException('Argument \'field\' must be supplied.', 1522959187);
461  }
462 
463  // Get and check current site
464  $site = $this->‪getCurrentSite();
465 
466  // Throws InvalidArgumentException in case language is not found which is fine
467  $language = $site->getLanguageById((int)$conf['language']);
468  if ($language->enabled()) {
469  $language = $language->toArray();
470  } else {
471  $language = null;
472  }
473 
474  // Check field for return exists
475  if ($language !== null && !isset($language[$conf['field']])) {
476  throw new \InvalidArgumentException('Invalid value \'' . $conf['field'] . '\' for argument \'field\' supplied.', 1524063160);
477  }
478 
479  return $this->‪jsonEncode($language[$conf['field']]);
480  }
481 }
‪TYPO3\CMS\Core\Site\Entity\SiteInterface
Definition: SiteInterface.php:25
‪TYPO3\CMS\Frontend\ContentObject\ContentDataProcessor
Definition: ContentDataProcessor.php:24
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\getCurrentSite
‪SiteInterface getCurrentSite()
Definition: LanguageMenuProcessor.php:268
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$contentDataProcessor
‪ContentDataProcessor $contentDataProcessor
Definition: LanguageMenuProcessor.php:233
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\prepareConfiguration
‪prepareConfiguration()
Definition: LanguageMenuProcessor.php:304
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\replacePlaceholderInRenderedMenuItem
‪array replacePlaceholderInRenderedMenuItem(array $menuItem)
Definition: LanguageMenuProcessor.php:416
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\getFieldAsJson
‪string getFieldAsJson(string $content, array $conf)
Definition: LanguageMenuProcessor.php:434
‪TYPO3\CMS\Frontend\DataProcessing
Definition: CommaSeparatedValueProcessor.php:2
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$menuConfig
‪array $menuConfig
Definition: LanguageMenuProcessor.php:88
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$removeConfigurationKeysForHmenu
‪array $removeConfigurationKeysForHmenu
Definition: LanguageMenuProcessor.php:80
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$menuTargetVariableName
‪string $menuTargetVariableName
Definition: LanguageMenuProcessor.php:229
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor
Definition: LanguageMenuProcessor.php:45
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getContentObject
‪AbstractContentObject null getContentObject($name)
Definition: ContentObjectRenderer.php:748
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$menuLevelConfig
‪array $menuLevelConfig
Definition: LanguageMenuProcessor.php:99
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\jsonEncode
‪string jsonEncode($value)
Definition: LanguageMenuProcessor.php:280
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\getTypoScriptFrontendController
‪TypoScriptFrontendController getTypoScriptFrontendController()
Definition: LanguageMenuProcessor.php:257
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\getConfigurationValue
‪string getConfigurationValue(string $key)
Definition: LanguageMenuProcessor.php:249
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$cObj
‪ContentObjectRenderer $cObj
Definition: LanguageMenuProcessor.php:52
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$menuDefaults
‪array $menuDefaults
Definition: LanguageMenuProcessor.php:223
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\buildConfiguration
‪buildConfiguration()
Definition: LanguageMenuProcessor.php:341
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\__construct
‪__construct()
Definition: LanguageMenuProcessor.php:238
‪TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface
Definition: DataProcessorInterface.php:22
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\validateAndBuildConfiguration
‪validateAndBuildConfiguration()
Definition: LanguageMenuProcessor.php:364
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:97
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\LINK_PLACEHOLDER
‪const LINK_PLACEHOLDER
Definition: LanguageMenuProcessor.php:46
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\validateConfiguration
‪validateConfiguration()
Definition: LanguageMenuProcessor.php:288
‪TYPO3\CMS\Frontend\Utility\CanonicalizationUtility
Definition: CanonicalizationUtility.php:25
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$allowedConfigurationKeys
‪array $allowedConfigurationKeys
Definition: LanguageMenuProcessor.php:65
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:91
‪TYPO3\CMS\Frontend\Utility\CanonicalizationUtility\getParamsToExcludeForCanonicalizedUrl
‪static array getParamsToExcludeForCanonicalizedUrl(int $pageId, array $additionalCanonicalizedUrlParameters=[])
Definition: CanonicalizationUtility.php:41
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$processorConfiguration
‪array $processorConfiguration
Definition: LanguageMenuProcessor.php:58
‪TYPO3\CMS\Core\Routing\SiteMatcher
Definition: SiteMatcher.php:53
‪TYPO3\CMS\Frontend\ContentObject\AbstractContentObject\render
‪string render($conf=[])
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\process
‪array process(ContentObjectRenderer $cObj, array $contentObjectConfiguration, array $processorConfiguration, array $processedData)
Definition: LanguageMenuProcessor.php:381