TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
MenuProcessor.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Frontend\DataProcessing;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
21 
60 {
61  const LINK_PLACEHOLDER = '###LINKPLACEHOLDER###';
62  const TARGET_PLACEHOLDER = '###TARGETPLACEHOLDER###';
63 
69  public $cObj;
70 
77 
85  'cache_period',
86  'entryLevel',
87  'entryLevel.',
88  'special',
89  'special.',
90  'minItems',
91  'minItems.',
92  'maxItems',
93  'maxItems.',
94  'begin',
95  'begin.',
96  'excludeUidList',
97  'excludeUidList.',
98  'excludeDoktypes',
99  'includeNotInMenu',
100  'alwaysActivePIDlist',
101  'alwaysActivePIDlist.',
102  'protectLvar',
103  'addQueryString',
104  'if',
105  'if.',
106  'levels',
107  'expandAll',
108  'includeSpacer',
109  'as',
110  'titleField',
111  'dataProcessing',
112  'dataProcessing.'
113  ];
114 
122  'levels',
123  'expandAll',
124  'includeSpacer',
125  'as',
126  'titleField',
127  'dataProcessing',
128  'dataProcessing.'
129  ];
130 
134  protected $menuConfig = [
135  'wrap' => '[|]'
136  ];
137 
141  protected $menuLevelConfig = [
142  'doNotLinkIt' => '1',
143  'wrapItemAndSub' => '{|}, |*| {|}, |*| {|}',
144  'stdWrap.' => [
145  'cObject' => 'COA',
146  'cObject.' => [
147  '10' => 'USER',
148  '10.' => [
149  'userFunc' => 'TYPO3\CMS\Frontend\DataProcessing\MenuProcessor->getDataAsJson',
150  'stdWrap.' => [
151  'wrap' => '"data":|'
152  ]
153  ],
154  '20' => 'TEXT',
155  '20.' => [
156  'field' => 'nav_title // title',
157  'trim' => '1',
158  'wrap' => ',"title":|',
159  'preUserFunc' => 'TYPO3\CMS\Frontend\DataProcessing\MenuProcessor->jsonEncodeUserFunc'
160  ],
161  '21' => 'TEXT',
162  '21.' => [
163  'value' => self::LINK_PLACEHOLDER,
164  'wrap' => ',"link":|',
165  ],
166  '22' => 'TEXT',
167  '22.' => [
168  'value' => self::TARGET_PLACEHOLDER,
169  'wrap' => ',"target":|',
170  ],
171  '30' => 'TEXT',
172  '30.' => [
173  'value' => '0',
174  'wrap' => ',"active":|'
175  ],
176  '40' => 'TEXT',
177  '40.' => [
178  'value' => '0',
179  'wrap' => ',"current":|'
180  ],
181  '50' => 'TEXT',
182  '50.' => [
183  'value' => '0',
184  'wrap' => ',"spacer":|'
185  ]
186  ]
187  ]
188  ];
189 
193  public $menuDefaults = [
194  'levels' => 1,
195  'expandAll' => 1,
196  'includeSpacer' => 0,
197  'as' => 'menu',
198  'titleField' => 'nav_title // title'
199  ];
200 
204  protected $menuLevels;
205 
209  protected $menuExpandAll;
210 
215 
219  protected $menuTitleField;
220 
225 
230 
234  public function __construct()
235  {
236  $this->contentDataProcessor = GeneralUtility::makeInstance(ContentDataProcessor::class);
237  }
238 
245  protected function getConfigurationValue($key)
246  {
247  return $this->cObj->stdWrapValue($key, $this->processorConfiguration, $this->menuDefaults[$key]);
248  }
249 
255  public function validateConfiguration()
256  {
257  $invalidArguments = [];
258  foreach ($this->processorConfiguration as $key => $value) {
259  if (!in_array($key, $this->allowedConfigurationKeys)) {
260  $invalidArguments[str_replace('.', '', $key)] = $key;
261  }
262  }
263  if (!empty($invalidArguments)) {
264  throw new \InvalidArgumentException('MenuProcessor Configuration contains invalid Arguments: ' . implode(', ', $invalidArguments), 1478806566);
265  }
266  }
267 
271  public function prepareConfiguration()
272  {
273  $this->menuConfig += $this->processorConfiguration;
274  // Filter configuration
275  foreach ($this->menuConfig as $key => $value) {
276  if (in_array($key, $this->removeConfigurationKeysForHmenu)) {
277  unset($this->menuConfig[$key]);
278  }
279  }
280  // Process special value
281  if (isset($this->menuConfig['special.']['value.'])) {
282  $this->menuConfig['special.']['value'] = $this->cObj->stdWrap($this->menuConfig['special.']['value'], $this->menuConfig['special.']['value.']);
283  unset($this->menuConfig['special.']['value.']);
284  }
285  }
286 
290  public function prepareLevelConfiguration()
291  {
292  $this->menuLevelConfig['stdWrap.']['cObject.'] = array_replace_recursive(
293  $this->menuLevelConfig['stdWrap.']['cObject.'],
294  [
295  '20.' => [
296  'field' => $this->menuTitleField,
297  ]
298  ]
299  );
300  }
301 
306  {
307  if ($this->menuConfig['special'] === 'language') {
308  $this->menuLevelConfig['stdWrap.']['cObject.'] = array_replace_recursive(
309  $this->menuLevelConfig['stdWrap.']['cObject.'],
310  [
311  '60' => 'TEXT',
312  '60.' => [
313  'value' => '1',
314  'wrap' => ',"available":|'
315  ],
316  '70' => 'TEXT',
317  '70.' => [
318  'value' => $this->menuConfig['special.']['value'],
319  'listNum.' => [
320  'stdWrap.' => [
321  'data' => 'register:count_HMENU_MENUOBJ',
322  'wrap' => '|-1'
323  ],
324  'splitChar' => ','
325  ],
326  'wrap' => ',"languageUid":"|"'
327  ]
328  ]
329  );
330  }
331  }
332 
336  public function buildConfiguration()
337  {
338  for ($i = 1; $i <= $this->menuLevels; $i++) {
339  $this->menuConfig[$i] = 'TMENU';
340  $this->menuConfig[$i . '.']['IProcFunc'] = 'TYPO3\CMS\Frontend\DataProcessing\MenuProcessor->replacePlaceholderInRenderedMenuItem';
341  if ($i > 1) {
342  $this->menuConfig[$i . '.']['stdWrap.']['wrap'] = ',"children": [|]';
343  }
344  $this->menuConfig[$i . '.']['expAll'] = $this->menuExpandAll;
345  $this->menuConfig[$i . '.']['NO'] = '1';
346  $this->menuConfig[$i . '.']['NO.'] = $this->menuLevelConfig;
347  if ($this->menuIncludeSpacer) {
348  $this->menuConfig[$i . '.']['SPC'] = '1';
349  $this->menuConfig[$i . '.']['SPC.'] = $this->menuConfig[$i . '.']['NO.'];
350  $this->menuConfig[$i . '.']['SPC.']['stdWrap.']['cObject.']['50.']['value'] = '1';
351  }
352  $this->menuConfig[$i . '.']['IFSUB'] = '1';
353  $this->menuConfig[$i . '.']['IFSUB.'] = $this->menuConfig[$i . '.']['NO.'];
354  $this->menuConfig[$i . '.']['ACT'] = '1';
355  $this->menuConfig[$i . '.']['ACT.'] = $this->menuConfig[$i . '.']['NO.'];
356  $this->menuConfig[$i . '.']['ACT.']['stdWrap.']['cObject.']['30.']['value'] = '1';
357  $this->menuConfig[$i . '.']['ACTIFSUB'] = '1';
358  $this->menuConfig[$i . '.']['ACTIFSUB.'] = $this->menuConfig[$i . '.']['ACT.'];
359  $this->menuConfig[$i . '.']['CUR'] = '1';
360  $this->menuConfig[$i . '.']['CUR.'] = $this->menuConfig[$i . '.']['ACT.'];
361  $this->menuConfig[$i . '.']['CUR.']['stdWrap.']['cObject.']['40.']['value'] = '1';
362  $this->menuConfig[$i . '.']['CURIFSUB'] = '1';
363  $this->menuConfig[$i . '.']['CURIFSUB.'] = $this->menuConfig[$i . '.']['CUR.'];
364  if ($this->menuConfig['special'] === 'language') {
365  $this->menuConfig[$i . '.']['USERDEF1'] = $this->menuConfig[$i . '.']['NO'];
366  $this->menuConfig[$i . '.']['USERDEF1.'] = $this->menuConfig[$i . '.']['NO.'];
367  $this->menuConfig[$i . '.']['USERDEF1.']['stdWrap.']['cObject.']['60.']['value'] = '0';
368  $this->menuConfig[$i . '.']['USERDEF2'] = $this->menuConfig[$i . '.']['ACT'];
369  $this->menuConfig[$i . '.']['USERDEF2.'] = $this->menuConfig[$i . '.']['ACT.'];
370  $this->menuConfig[$i . '.']['USERDEF2.']['stdWrap.']['cObject.']['60.']['value'] = '0';
371  }
372  }
373  }
374 
382  public function process(ContentObjectRenderer $cObj, array $contentObjectConfiguration, array $processorConfiguration, array $processedData)
383  {
384  $this->cObj = $cObj;
385  $this->processorConfiguration = $processorConfiguration;
386 
387  // Get Configuration
388  $this->menuLevels = (int)$this->getConfigurationValue('levels') ?: 1;
389  $this->menuExpandAll = (int)$this->getConfigurationValue('expandAll');
390  $this->menuIncludeSpacer = (int)$this->getConfigurationValue('includeSpacer');
391  $this->menuTargetVariableName = $this->getConfigurationValue('as');
392  $this->menuTitleField = $this->getConfigurationValue('titleField');
393 
394  // Validate Configuration
395  $this->validateConfiguration();
396 
397  // Build Configuration
398  $this->prepareConfiguration();
399  $this->prepareLevelConfiguration();
401  $this->buildConfiguration();
402 
403  // Process Configuration
404  $menuContentObject = $cObj->getContentObject('HMENU');
405  $renderedMenu = $menuContentObject->render($this->menuConfig);
406  if (!$renderedMenu) {
407  return $processedData;
408  }
409 
410  // Process menu
411  $menu = json_decode($renderedMenu, true);
412  $processedMenu = [];
413 
414  foreach ($menu as $key => $page) {
415  $processedMenu[$key] = $this->processAdditionalDataProcessors($page, $processorConfiguration);
416  }
417 
418  // Return processed data
419  $processedData[$this->menuTargetVariableName] = $processedMenu;
420  return $processedData;
421  }
422 
429  protected function processAdditionalDataProcessors($page, $processorConfiguration)
430  {
431  if (is_array($page['children'])) {
432  foreach ($page['children'] as $key => $item) {
433  $page['children'][$key] = $this->processAdditionalDataProcessors($item, $processorConfiguration);
434  }
435  }
437  $recordContentObjectRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class);
438  $recordContentObjectRenderer->start($page['data'], 'pages');
439  $processedPage = $this->contentDataProcessor->process($recordContentObjectRenderer, $processorConfiguration, $page);
440  return $processedPage;
441  }
442 
448  public function getDataAsJson()
449  {
450  return $this->jsonEncode($this->cObj->data);
451  }
452 
460  public function jsonEncodeUserFunc($content, $conf)
461  {
462  $content = $this->jsonEncode($content);
463  return $content;
464  }
465 
472  public function jsonEncode($value)
473  {
474  return json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE);
475  }
476 
484  public function replacePlaceholderInRenderedMenuItem($menuItem, $conf)
485  {
486  $link = $this->jsonEncode($menuItem['linkHREF']['HREF']);
487  $target = $this->jsonEncode($menuItem['linkHREF']['TARGET']);
488 
489  $menuItem['parts']['title'] = str_replace(self::LINK_PLACEHOLDER, $link, $menuItem['parts']['title']);
490  $menuItem['parts']['title'] = str_replace(self::TARGET_PLACEHOLDER, $target, $menuItem['parts']['title']);
491 
492  return $menuItem;
493  }
494 }
static makeInstance($className,...$constructorArguments)
process(ContentObjectRenderer $cObj, array $contentObjectConfiguration, array $processorConfiguration, array $processedData)