‪TYPO3CMS  10.4
LanguageMenuProcessor.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
30 
48 {
49  protected const ‪LINK_PLACEHOLDER = '###LINKPLACEHOLDER###';
50 
56  public ‪$cObj;
57 
64 
71  protected ‪$allowedConfigurationKeys = [
72  'if',
73  'if.',
74  'languages',
75  'languages.',
76  'as',
77  'addQueryString',
78  'addQueryString.'
79  ];
80 
88  'languages',
89  'languages.',
90  'as'
91  ];
92 
96  protected ‪$menuConfig = [
97  'special' => 'language',
98  'addQueryString' => 1,
99  'addQueryString.' => [
100  'method' => 'GET'
101  ],
102  'wrap' => '[|]'
103  ];
104 
108  protected ‪$menuLevelConfig = [
109  'doNotLinkIt' => '1',
110  'wrapItemAndSub' => '{|}, |*| {|}, |*| {|}',
111  'stdWrap.' => [
112  'cObject' => 'COA',
113  'cObject.' => [
114  '1' => 'LOAD_REGISTER',
115  '1.' => [
116  'languageId.' => [
117  'cObject' => 'TEXT',
118  'cObject.' => [
119  'value.' => [
120  'data' => 'register:languages_HMENU'
121  ],
122  'listNum.' => [
123  'stdWrap.' => [
124  'data' => 'register:count_HMENU_MENUOBJ',
125  'wrap' => '|-1'
126  ],
127  'splitChar' => ','
128  ]
129  ]
130  ]
131  ],
132  '10' => 'TEXT',
133  '10.' => [
134  'stdWrap.' => [
135  'data' => 'register:languageId'
136  ],
137  'wrap' => '"languageId":|'
138  ],
139  '11' => 'USER',
140  '11.' => [
141  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
142  'language.' => [
143  'data' => 'register:languageId'
144  ],
145  'field' => 'locale',
146  'stdWrap.' => [
147  'wrap' => ',"locale":|'
148  ]
149  ],
150  '20' => 'USER',
151  '20.' => [
152  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
153  'language.' => [
154  'data' => 'register:languageId'
155  ],
156  'field' => 'title',
157  'stdWrap.' => [
158  'wrap' => ',"title":|'
159  ]
160  ],
161  '21' => 'USER',
162  '21.' => [
163  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
164  'language.' => [
165  'data' => 'register:languageId'
166  ],
167  'field' => 'navigationTitle',
168  'stdWrap.' => [
169  'wrap' => ',"navigationTitle":|'
170  ]
171  ],
172  '22' => 'USER',
173  '22.' => [
174  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
175  'language.' => [
176  'data' => 'register:languageId'
177  ],
178  'field' => 'twoLetterIsoCode',
179  'stdWrap.' => [
180  'wrap' => ',"twoLetterIsoCode":|'
181  ]
182  ],
183  '23' => 'USER',
184  '23.' => [
185  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
186  'language.' => [
187  'data' => 'register:languageId'
188  ],
189  'field' => 'hreflang',
190  'stdWrap.' => [
191  'wrap' => ',"hreflang":|'
192  ]
193  ],
194  '24' => 'USER',
195  '24.' => [
196  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
197  'language.' => [
198  'data' => 'register:languageId'
199  ],
200  'field' => 'direction',
201  'stdWrap.' => [
202  'wrap' => ',"direction":|'
203  ]
204  ],
205  '25' => 'USER',
206  '25.' => [
207  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor->getFieldAsJson',
208  'language.' => [
209  'data' => 'register:languageId'
210  ],
211  'field' => 'flag',
212  'stdWrap.' => [
213  'wrap' => ',"flag":|'
214  ]
215  ],
216  '90' => 'TEXT',
217  '90.' => [
218  'value' => ‪self::LINK_PLACEHOLDER,
219  'wrap' => ',"link":|',
220  ],
221  '91' => 'TEXT',
222  '91.' => [
223  'value' => '0',
224  'wrap' => ',"active":|'
225  ],
226  '92' => 'TEXT',
227  '92.' => [
228  'value' => '0',
229  'wrap' => ',"current":|'
230  ],
231  '93' => 'TEXT',
232  '93.' => [
233  'value' => '1',
234  'wrap' => ',"available":|'
235  ],
236  '99' => 'RESTORE_REGISTER'
237  ]
238  ]
239  ];
240 
244  protected ‪$menuDefaults = [
245  'as' => 'languagemenu'
246  ];
247 
251  protected ‪$menuTargetVariableName;
252 
256  protected ‪$contentDataProcessor;
257 
261  public function ‪__construct()
262  {
263  $this->contentDataProcessor = GeneralUtility::makeInstance(ContentDataProcessor::class);
264  }
265 
272  protected function ‪getConfigurationValue(string $key): string
273  {
274  return $this->cObj->stdWrapValue($key, $this->processorConfiguration, $this->menuDefaults[$key]);
275  }
276 
280  protected function ‪getTypoScriptFrontendController(): TypoScriptFrontendController
281  {
282  return ‪$GLOBALS['TSFE'];
283  }
284 
290  protected function ‪getCurrentSite(): ‪SiteInterface
291  {
292  try {
293  return GeneralUtility::makeInstance(SiteFinder::class)
294  ->getSiteByPageId((int)$this->‪getTypoScriptFrontendController()->id);
295  } catch (SiteNotFoundException $e) {
296  return new NullSite();
297  }
298  }
299 
306  protected function ‪jsonEncode($value): string
307  {
308  return json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE);
309  }
310 
314  protected function ‪validateConfiguration()
315  {
316  $invalidArguments = [];
317  foreach ($this->processorConfiguration as $key => $value) {
318  if (!in_array($key, $this->allowedConfigurationKeys)) {
319  $invalidArguments[str_replace('.', '', $key)] = $key;
320  }
321  }
322  if (!empty($invalidArguments)) {
323  throw new \InvalidArgumentException('LanguageMenuProcessor configuration contains invalid arguments: ' . implode(', ', $invalidArguments), 1522959188);
324  }
325  }
326 
330  protected function ‪prepareConfiguration(): void
331  {
332  $this->menuConfig = array_merge($this->menuConfig, $this->processorConfiguration);
333 
334  // Process languages
335  if (empty($this->menuConfig['languages']) && empty($this->menuConfig['languages.'])) {
336  $this->menuConfig['special.']['value'] = 'auto';
337  } elseif (!empty($this->menuConfig['languages.'])) {
338  $this->menuConfig['special.']['value'] = $this->cObj->stdWrap($this->menuConfig['languages'], $this->menuConfig['languages.']);
339  } else {
340  $this->menuConfig['special.']['value'] = $this->menuConfig['languages'];
341  }
342 
343  // Filter configuration
344  foreach ($this->menuConfig as $key => $value) {
345  if (in_array($key, $this->removeConfigurationKeysForHmenu, true)) {
346  unset($this->menuConfig[$key]);
347  }
348  }
349 
351  (int)$this->‪getTypoScriptFrontendController()->id,
352  (array)‪$GLOBALS['TYPO3_CONF_VARS']['FE']['additionalCanonicalizedUrlParameters']
353  );
354 
355  $this->menuConfig['addQueryString.']['exclude'] = implode(
356  ',',
357  array_merge(
358  ‪GeneralUtility::trimExplode(',', $this->menuConfig['addQueryString.']['exclude'] ?? '', true),
359  $paramsToExclude
360  )
361  );
362  }
363 
367  protected function ‪buildConfiguration(): void
368  {
369  $this->menuConfig['1'] = 'TMENU';
370  $this->menuConfig['1.']['IProcFunc'] = LanguageMenuProcessor::class . '->replacePlaceholderInRenderedMenuItem';
371  $this->menuConfig['1.']['NO'] = '1';
372  $this->menuConfig['1.']['NO.'] = ‪$this->menuLevelConfig;
373  $this->menuConfig['1.']['ACT'] = $this->menuConfig['1.']['NO'];
374  $this->menuConfig['1.']['ACT.'] = $this->menuConfig['1.']['NO.'];
375  $this->menuConfig['1.']['ACT.']['stdWrap.']['cObject.']['91.']['value'] = '1';
376  $this->menuConfig['1.']['CUR'] = $this->menuConfig['1.']['ACT'];
377  $this->menuConfig['1.']['CUR.'] = $this->menuConfig['1.']['ACT.'];
378  $this->menuConfig['1.']['CUR.']['stdWrap.']['cObject.']['92.']['value'] = '1';
379  $this->menuConfig['1.']['USERDEF1'] = $this->menuConfig['1.']['NO'];
380  $this->menuConfig['1.']['USERDEF1.'] = $this->menuConfig['1.']['NO.'];
381  $this->menuConfig['1.']['USERDEF1.']['stdWrap.']['cObject.']['93.']['value'] = '0';
382  $this->menuConfig['1.']['USERDEF2'] = $this->menuConfig['1.']['ACT'];
383  $this->menuConfig['1.']['USERDEF2.'] = $this->menuConfig['1.']['ACT.'];
384  $this->menuConfig['1.']['USERDEF2.']['stdWrap.']['cObject.']['93.']['value'] = '0';
385  }
386 
390  protected function ‪validateAndBuildConfiguration(): void
391  {
392  // Validate Configuration
393  $this->‪validateConfiguration();
394 
395  // Build Configuration
396  $this->‪prepareConfiguration();
397  $this->‪buildConfiguration();
398  }
399 
407  public function ‪process(‪ContentObjectRenderer ‪$cObj, array $contentObjectConfiguration, array ‪$processorConfiguration, array $processedData): array
408  {
409  $this->cObj = ‪$cObj;
410  $this->processorConfiguration = ‪$processorConfiguration;
411 
412  // Get Configuration
413  $this->menuTargetVariableName = $this->‪getConfigurationValue('as');
414 
415  // Validate and Build Configuration
417 
418  // Process Configuration
419  $menuContentObject = ‪$cObj->‪getContentObject('HMENU');
420  $renderedMenu = $menuContentObject->‪render($this->menuConfig);
421  if ($renderedMenu) {
422  // Process menu
423  $menu = json_decode($renderedMenu, true);
424  $processedMenu = [];
425 
426  foreach ($menu as $key => $language) {
427  $processedMenu[$key] = $language;
428  }
429 
430  $processedData[‪$this->menuTargetVariableName] = $processedMenu;
431  }
432 
433  return $processedData;
434  }
435 
442  public function ‪replacePlaceholderInRenderedMenuItem(array $menuItem): array
443  {
444  $link = $this->‪jsonEncode($menuItem['linkHREF']['HREF']);
445 
446  $menuItem['parts']['title'] = str_replace(self::LINK_PLACEHOLDER, $link, $menuItem['parts']['title']);
447 
448  return $menuItem;
449  }
450 
460  public function ‪getFieldAsJson(string $content, array $conf): string
461  {
462  // Support of stdWrap for parameters
463  if (isset($conf['language.'])) {
464  $conf['language'] = $this->cObj->stdWrap($conf['language'], $conf['language.']);
465  unset($conf['language.']);
466  }
467  if (isset($conf['field.'])) {
468  $conf['field'] = $this->cObj->stdWrap($conf['field'], $conf['field.']);
469  unset($conf['field.']);
470  }
471 
472  // Check required fields
473  if ($conf['language'] === '') {
474  throw new \InvalidArgumentException('Argument \'language\' must be supplied.', 1522959186);
475  }
476  if ($conf['field'] === '') {
477  throw new \InvalidArgumentException('Argument \'field\' must be supplied.', 1522959187);
478  }
479 
480  // Get and check current site
481  $site = $this->‪getCurrentSite();
482 
483  // Throws InvalidArgumentException in case language is not found which is fine
484  $language = $site->getLanguageById((int)$conf['language']);
485  if ($language->enabled()) {
486  $language = $language->toArray();
487  } else {
488  $language = null;
489  }
490 
491  // Check field for return exists
492  if ($language !== null && !isset($language[$conf['field']])) {
493  throw new \InvalidArgumentException('Invalid value \'' . $conf['field'] . '\' for argument \'field\' supplied.', 1524063160);
494  }
495 
496  return $this->‪jsonEncode($language[$conf['field']]);
497  }
498 }
‪TYPO3\CMS\Core\Site\Entity\SiteInterface
Definition: SiteInterface.php:26
‪TYPO3\CMS\Frontend\ContentObject\ContentDataProcessor
Definition: ContentDataProcessor.php:25
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\getCurrentSite
‪SiteInterface getCurrentSite()
Definition: LanguageMenuProcessor.php:281
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$contentDataProcessor
‪ContentDataProcessor $contentDataProcessor
Definition: LanguageMenuProcessor.php:247
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\prepareConfiguration
‪prepareConfiguration()
Definition: LanguageMenuProcessor.php:321
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\replacePlaceholderInRenderedMenuItem
‪array replacePlaceholderInRenderedMenuItem(array $menuItem)
Definition: LanguageMenuProcessor.php:433
‪TYPO3\CMS\Core\Site\Entity\NullSite
Definition: NullSite.php:32
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\getFieldAsJson
‪string getFieldAsJson(string $content, array $conf)
Definition: LanguageMenuProcessor.php:451
‪TYPO3\CMS\Core\Exception\SiteNotFoundException
Definition: SiteNotFoundException.php:26
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Frontend\DataProcessing
Definition: CommaSeparatedValueProcessor.php:16
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$menuConfig
‪array $menuConfig
Definition: LanguageMenuProcessor.php:91
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$removeConfigurationKeysForHmenu
‪array $removeConfigurationKeysForHmenu
Definition: LanguageMenuProcessor.php:83
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$menuTargetVariableName
‪string $menuTargetVariableName
Definition: LanguageMenuProcessor.php:243
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor
Definition: LanguageMenuProcessor.php:48
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getContentObject
‪AbstractContentObject null getContentObject($name)
Definition: ContentObjectRenderer.php:754
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$menuLevelConfig
‪array $menuLevelConfig
Definition: LanguageMenuProcessor.php:102
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\jsonEncode
‪string jsonEncode($value)
Definition: LanguageMenuProcessor.php:297
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\getTypoScriptFrontendController
‪TypoScriptFrontendController getTypoScriptFrontendController()
Definition: LanguageMenuProcessor.php:271
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\getConfigurationValue
‪string getConfigurationValue(string $key)
Definition: LanguageMenuProcessor.php:263
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$cObj
‪ContentObjectRenderer $cObj
Definition: LanguageMenuProcessor.php:55
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$menuDefaults
‪array $menuDefaults
Definition: LanguageMenuProcessor.php:237
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\buildConfiguration
‪buildConfiguration()
Definition: LanguageMenuProcessor.php:358
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\__construct
‪__construct()
Definition: LanguageMenuProcessor.php:252
‪TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface
Definition: DataProcessorInterface.php:23
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\validateAndBuildConfiguration
‪validateAndBuildConfiguration()
Definition: LanguageMenuProcessor.php:381
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:98
‪$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:49
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\validateConfiguration
‪validateConfiguration()
Definition: LanguageMenuProcessor.php:305
‪TYPO3\CMS\Frontend\Utility\CanonicalizationUtility
Definition: CanonicalizationUtility.php:26
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$allowedConfigurationKeys
‪array $allowedConfigurationKeys
Definition: LanguageMenuProcessor.php:68
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:97
‪TYPO3\CMS\Frontend\Utility\CanonicalizationUtility\getParamsToExcludeForCanonicalizedUrl
‪static array getParamsToExcludeForCanonicalizedUrl(int $pageId, array $additionalCanonicalizedUrlParameters=[])
Definition: CanonicalizationUtility.php:42
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor\$processorConfiguration
‪array $processorConfiguration
Definition: LanguageMenuProcessor.php:61
‪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:398