‪TYPO3CMS  11.5
BackendLayoutView.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
19 use TYPO3\CMS\Backend\Utility\BackendUtility;
31 
37 {
42 
46  protected ‪$selectedCombinedIdentifier = [];
47 
51  protected ‪$selectedBackendLayout = [];
52 
56  public function ‪__construct()
57  {
59  }
60 
64  protected function ‪initializeDataProviderCollection()
65  {
66  ‪$dataProviderCollection = GeneralUtility::makeInstance(DataProviderCollection::class);
67  ‪$dataProviderCollection->‪add('default', DefaultDataProvider::class);
68 
69  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider'])) {
70  $dataProviders = (array)‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider'];
71  foreach ($dataProviders as $identifier => $className) {
72  ‪$dataProviderCollection->‪add($identifier, $className);
73  }
74  }
75 
77  }
78 
83  {
84  $this->dataProviderCollection = ‪$dataProviderCollection;
85  }
86 
90  public function ‪getDataProviderCollection()
91  {
93  }
94 
108  public function ‪addBackendLayoutItems(array &$parameters)
109  {
110  $pageId = $this->‪determinePageId($parameters['table'], $parameters['row']) ?: 0;
111  $pageTsConfig = (array)BackendUtility::getPagesTSconfig($pageId);
112  $identifiersToBeExcluded = $this->‪getIdentifiersToBeExcluded($pageTsConfig);
113 
114  $dataProviderContext = $this->‪createDataProviderContext()
115  ->‪setPageId($pageId)
116  ->‪setData($parameters['row'])
117  ->‪setTableName($parameters['table'])
118  ->‪setFieldName($parameters['field'])
119  ->‪setPageTsConfig($pageTsConfig);
120 
121  $backendLayoutCollections = $this->‪getDataProviderCollection()->‪getBackendLayoutCollections($dataProviderContext);
122  foreach ($backendLayoutCollections as $backendLayoutCollection) {
123  $combinedIdentifierPrefix = '';
124  if ($backendLayoutCollection->getIdentifier() !== 'default') {
125  $combinedIdentifierPrefix = $backendLayoutCollection->‪getIdentifier() . '__';
126  }
127 
128  foreach ($backendLayoutCollection->getAll() as $backendLayout) {
129  $combinedIdentifier = $combinedIdentifierPrefix . $backendLayout->getIdentifier();
130 
131  if (in_array($combinedIdentifier, $identifiersToBeExcluded, true)) {
132  continue;
133  }
134 
135  $parameters['items'][] = [
136  $this->‪getLanguageService()->‪sL($backendLayout->getTitle()),
137  $combinedIdentifier,
138  $backendLayout->getIconPath(),
139  ];
140  }
141  }
142  }
143 
151  protected function ‪determinePageId($tableName, array $data)
152  {
153  if (strpos((string)$data['uid'], 'NEW') === 0) {
154  // negative uid_pid values of content elements indicate that the element
155  // has been inserted after an existing element so there is no pid to get
156  // the backendLayout for and we have to get that first
157  if ($data['pid'] < 0) {
158  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
159  ->getQueryBuilderForTable($tableName);
160  $queryBuilder->getRestrictions()
161  ->removeAll();
162  $pageId = $queryBuilder
163  ->select('pid')
164  ->from($tableName)
165  ->where(
166  $queryBuilder->expr()->eq(
167  'uid',
168  $queryBuilder->createNamedParameter(abs($data['pid']), ‪Connection::PARAM_INT)
169  )
170  )
171  ->executeQuery()
172  ->fetchOne();
173  } else {
174  $pageId = $data['pid'];
175  }
176  } elseif ($tableName === 'pages') {
177  $pageId = $data['uid'];
178  } else {
179  $pageId = $data['pid'];
180  }
181 
182  return $pageId;
183  }
184 
191  public function ‪getSelectedCombinedIdentifier($pageId)
192  {
193  if (!isset($this->selectedCombinedIdentifier[$pageId])) {
194  $page = $this->‪getPage($pageId);
195  $this->selectedCombinedIdentifier[$pageId] = (string)($page['backend_layout'] ?? null);
196 
197  if ($this->selectedCombinedIdentifier[$pageId] === '-1') {
198  // If it is set to "none" - don't use any
199  $this->selectedCombinedIdentifier[$pageId] = false;
200  } elseif ($this->selectedCombinedIdentifier[$pageId] === '' || $this->selectedCombinedIdentifier[$pageId] === '0') {
201  // If it not set check the root-line for a layout on next level and use this
202  // (root-line starts with current page and has page "0" at the end)
203  $rootLine = $this->‪getRootLine($pageId);
204  // Remove first and last element (current and root page)
205  array_shift($rootLine);
206  array_pop($rootLine);
207  foreach ($rootLine as $rootLinePage) {
208  $this->selectedCombinedIdentifier[$pageId] = (string)$rootLinePage['backend_layout_next_level'];
209  if ($this->selectedCombinedIdentifier[$pageId] === '-1') {
210  // If layout for "next level" is set to "none" - don't use any and stop searching
211  $this->selectedCombinedIdentifier[$pageId] = false;
212  break;
213  }
214  if ($this->selectedCombinedIdentifier[$pageId] !== '' && $this->selectedCombinedIdentifier[$pageId] !== '0') {
215  // Stop searching if a layout for "next level" is set
216  break;
217  }
218  }
219  }
220  }
221  // If it is set to a positive value use this
222  return $this->selectedCombinedIdentifier[$pageId];
223  }
224 
231  protected function ‪getIdentifiersToBeExcluded(array $pageTSconfig)
232  {
233  $identifiersToBeExcluded = [];
234 
235  if (‪ArrayUtility::isValidPath($pageTSconfig, 'options./backendLayout./exclude')) {
236  $identifiersToBeExcluded = ‪GeneralUtility::trimExplode(
237  ',',
238  ‪ArrayUtility::getValueByPath($pageTSconfig, 'options./backendLayout./exclude'),
239  true
240  );
241  }
242 
243  return $identifiersToBeExcluded;
244  }
245 
253  public function ‪colPosListItemProcFunc(array $parameters)
254  {
255  $pageId = $this->‪determinePageId($parameters['table'], $parameters['row']);
256 
257  if ($pageId !== false) {
258  $parameters['items'] = $this->‪addColPosListLayoutItems($pageId, $parameters['items']);
259  }
260  }
261 
269  protected function ‪addColPosListLayoutItems($pageId, $items)
270  {
271  $layout = $this->‪getSelectedBackendLayout($pageId);
272  if ($layout && !empty($layout['__items'])) {
273  $items = $layout['__items'];
274  }
275  return $items;
276  }
277 
284  public function ‪getColPosListItemsParsed($id)
285  {
286  $tsConfig = BackendUtility::getPagesTSconfig($id)['TCEFORM.']['tt_content.']['colPos.'] ?? [];
287  $tcaConfig = ‪$GLOBALS['TCA']['tt_content']['columns']['colPos']['config'] ?? [];
288  $tcaItems = $tcaConfig['items'];
289  $tcaItems = $this->‪addItems($tcaItems, $tsConfig['addItems.'] ?? []);
290  if (isset($tcaConfig['itemsProcFunc']) && $tcaConfig['itemsProcFunc']) {
291  $tcaItems = $this->‪addColPosListLayoutItems($id, $tcaItems);
292  }
293  if (!empty($tsConfig['removeItems'])) {
294  foreach (‪GeneralUtility::trimExplode(',', $tsConfig['removeItems'], true) as $removeId) {
295  foreach ($tcaItems as $key => $item) {
296  if ($item[1] == $removeId) {
297  unset($tcaItems[$key]);
298  }
299  }
300  }
301  }
302  return $tcaItems;
303  }
304 
316  protected function ‪addItems($items, $iArray)
317  {
318  $languageService = $this->‪getLanguageService();
319  if (is_array($iArray)) {
320  foreach ($iArray as $value => $label) {
321  // if the label is an array (that means it is a subelement
322  // like "34.icon = mylabel.png", skip it (see its usage below)
323  if (is_array($label)) {
324  continue;
325  }
326  // check if the value "34 = mylabel" also has a "34.icon = myimage.png"
327  if (isset($iArray[$value . '.']) && $iArray[$value . '.']['icon']) {
328  $icon = $iArray[$value . '.']['icon'];
329  } else {
330  $icon = '';
331  }
332  $items[] = [$languageService->sL($label), $value, $icon];
333  }
334  }
335  return $items;
336  }
337 
344  public function ‪getSelectedBackendLayout($pageId)
345  {
346  $layout = $this->‪getBackendLayoutForPage((int)$pageId);
347  if ($layout instanceof ‪BackendLayout) {
348  return $layout->getStructure();
349  }
350  return null;
351  }
352 
358  public function ‪getBackendLayoutForPage(int $pageId): ?‪BackendLayout
359  {
360  if (isset($this->selectedBackendLayout[$pageId])) {
361  return $this->selectedBackendLayout[$pageId];
362  }
364  // If no backend layout is selected, use default
365  if (empty(‪$selectedCombinedIdentifier)) {
366  ‪$selectedCombinedIdentifier = 'default';
367  }
369  // If backend layout is not found available anymore, use default
370  if ($backendLayout === null) {
371  $backendLayout = $this->‪getDataProviderCollection()->‪getBackendLayout('default', $pageId);
372  }
373 
374  if ($backendLayout instanceof ‪BackendLayout) {
375  $this->selectedBackendLayout[$pageId] = $backendLayout;
376  }
377  return $backendLayout;
378  }
379 
385  public function ‪parseStructure(‪BackendLayout $backendLayout): array
386  {
387  ‪$parser = GeneralUtility::makeInstance(TypoScriptParser::class);
388  $conditionMatcher = GeneralUtility::makeInstance(ConditionMatcher::class);
389  ‪$parser->parse(‪TypoScriptParser::checkIncludeLines($backendLayout->‪getConfiguration()), $conditionMatcher);
390 
391  $backendLayoutData = [];
392  $backendLayoutData['config'] = $backendLayout->‪getConfiguration();
393  $backendLayoutData['__config'] = ‪$parser->setup;
394  $backendLayoutData['__items'] = [];
395  $backendLayoutData['__colPosList'] = [];
396  $backendLayoutData['usedColumns'] = [];
397 
398  // create items and colPosList
399  if (!empty($backendLayoutData['__config']['backend_layout.']['rows.'])) {
400  $rows = $backendLayoutData['__config']['backend_layout.']['rows.'];
401  ksort($rows);
402  foreach ($rows as $row) {
403  if (!empty($row['columns.'])) {
404  foreach ($row['columns.'] as $column) {
405  if (!isset($column['colPos'])) {
406  continue;
407  }
408  $backendLayoutData['__items'][] = [
409  $this->‪getColumnName($column),
410  $column['colPos'],
411  null,
412  ];
413  $backendLayoutData['__colPosList'][] = $column['colPos'];
414  $backendLayoutData['usedColumns'][(int)$column['colPos']] = $column['name'];
415  }
416  }
417  }
418  }
419  return $backendLayoutData;
420  }
421 
428  public static function ‪getDefaultColumnLayout()
429  {
430  return '
431  backend_layout {
432  colCount = 1
433  rowCount = 1
434  rows {
435  1 {
436  columns {
437  1 {
438  name = LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.1
439  colPos = 0
440  }
441  }
442  }
443  }
444  }
445  ';
446  }
447 
454  protected function ‪getPage($pageId)
455  {
456  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
457  ->getQueryBuilderForTable('pages');
458  $queryBuilder->getRestrictions()
459  ->removeAll();
460  $page = $queryBuilder
461  ->select('uid', 'pid', 'backend_layout')
462  ->from('pages')
463  ->where(
464  $queryBuilder->expr()->eq(
465  'uid',
466  $queryBuilder->createNamedParameter($pageId, ‪Connection::PARAM_INT)
467  )
468  )
469  ->executeQuery()
470  ->fetchAssociative();
471  BackendUtility::workspaceOL('pages', $page);
472 
473  return $page;
474  }
475 
482  protected function ‪getRootLine($pageId)
483  {
484  return BackendUtility::BEgetRootLine($pageId, '', true);
485  }
486 
490  protected function ‪createDataProviderContext()
491  {
492  return GeneralUtility::makeInstance(DataProviderContext::class);
493  }
494 
498  protected function ‪getLanguageService()
499  {
500  return ‪$GLOBALS['LANG'];
501  }
502 
509  protected function ‪getColumnName($column)
510  {
511  $columnName = $column['name'];
512 
513  if (str_starts_with($columnName, 'LLL:')) {
514  $columnName = $this->‪getLanguageService()->‪sL($columnName);
515  }
516 
517  return $columnName;
518  }
519 }
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderContext\setPageId
‪DataProviderContext setPageId($pageId)
Definition: DataProviderContext.php:57
‪TYPO3\CMS\Backend\View\BackendLayoutView\determinePageId
‪int false determinePageId($tableName, array $data)
Definition: BackendLayoutView.php:148
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:999
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderContext\setTableName
‪DataProviderContext setTableName($tableName)
Definition: DataProviderContext.php:75
‪TYPO3\CMS\Backend\View\BackendLayoutView\getSelectedBackendLayout
‪array null getSelectedBackendLayout($pageId)
Definition: BackendLayoutView.php:341
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:49
‪TYPO3\CMS\Backend\View\BackendLayoutView\addColPosListLayoutItems
‪array addColPosListLayoutItems($pageId, $items)
Definition: BackendLayoutView.php:266
‪TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser
Definition: TypoScriptParser.php:36
‪TYPO3\CMS\Backend\View
Definition: ArrayBrowser.php:18
‪TYPO3\CMS\Backend\View\BackendLayoutView\colPosListItemProcFunc
‪colPosListItemProcFunc(array $parameters)
Definition: BackendLayoutView.php:250
‪TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher
Definition: ConditionMatcher.php:31
‪TYPO3\CMS\Backend\View\BackendLayoutView\getIdentifiersToBeExcluded
‪array getIdentifiersToBeExcluded(array $pageTSconfig)
Definition: BackendLayoutView.php:228
‪TYPO3\CMS\Backend\View\BackendLayoutView\getRootLine
‪array getRootLine($pageId)
Definition: BackendLayoutView.php:479
‪TYPO3\CMS\Core\Utility\ArrayUtility\isValidPath
‪static bool isValidPath(array $array, $path, $delimiter='/')
Definition: ArrayUtility.php:144
‪TYPO3\CMS\Backend\View\BackendLayoutView\$selectedBackendLayout
‪array $selectedBackendLayout
Definition: BackendLayoutView.php:48
‪$parser
‪$parser
Definition: annotationChecker.php:110
‪TYPO3\CMS\Backend\View\BackendLayoutView\createDataProviderContext
‪DataProviderContext createDataProviderContext()
Definition: BackendLayoutView.php:487
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderCollection
Definition: DataProviderCollection.php:25
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderContext\setFieldName
‪DataProviderContext setFieldName($fieldName)
Definition: DataProviderContext.php:93
‪TYPO3\CMS\Core\Localization\LanguageService\sL
‪string sL($input)
Definition: LanguageService.php:161
‪TYPO3\CMS\Backend\View\BackendLayoutView\parseStructure
‪array parseStructure(BackendLayout $backendLayout)
Definition: BackendLayoutView.php:382
‪TYPO3\CMS\Backend\View\BackendLayoutView\$dataProviderCollection
‪DataProviderCollection $dataProviderCollection
Definition: BackendLayoutView.php:40
‪TYPO3\CMS\Backend\View\BackendLayoutView\setDataProviderCollection
‪setDataProviderCollection(DataProviderCollection $dataProviderCollection)
Definition: BackendLayoutView.php:79
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderContext\setPageTsConfig
‪DataProviderContext setPageTsConfig(array $pageTsConfig)
Definition: DataProviderContext.php:129
‪TYPO3\CMS\Backend\View\BackendLayoutView\initializeDataProviderCollection
‪initializeDataProviderCollection()
Definition: BackendLayoutView.php:61
‪TYPO3\CMS\Backend\View\BackendLayoutView\getPage
‪array false null getPage($pageId)
Definition: BackendLayoutView.php:451
‪TYPO3\CMS\Backend\View\BackendLayoutView\getColumnName
‪string getColumnName($column)
Definition: BackendLayoutView.php:506
‪TYPO3\CMS\Core\Utility\ArrayUtility\getValueByPath
‪static mixed getValueByPath(array $array, $path, $delimiter='/')
Definition: ArrayUtility.php:180
‪TYPO3\CMS\Backend\View\BackendLayoutView\getLanguageService
‪LanguageService getLanguageService()
Definition: BackendLayoutView.php:495
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderCollection\add
‪add($identifier, $classNameOrObject)
Definition: DataProviderCollection.php:42
‪TYPO3\CMS\Backend\View\BackendLayout\BackendLayoutCollection\getIdentifier
‪string getIdentifier()
Definition: BackendLayoutCollection.php:42
‪TYPO3\CMS\Backend\View\BackendLayoutView\__construct
‪__construct()
Definition: BackendLayoutView.php:53
‪TYPO3\CMS\Backend\View\BackendLayoutView\getDefaultColumnLayout
‪static string getDefaultColumnLayout()
Definition: BackendLayoutView.php:425
‪TYPO3\CMS\Backend\View\BackendLayout\BackendLayout\getConfiguration
‪string getConfiguration()
Definition: BackendLayout.php:164
‪TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser\checkIncludeLines
‪static string array checkIncludeLines($string, $cycle_counter=1, $returnFiles=false, $parentFilenameOrPath='')
Definition: TypoScriptParser.php:680
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderCollection\getBackendLayoutCollections
‪array BackendLayoutCollection[] getBackendLayoutCollections(DataProviderContext $dataProviderContext)
Definition: DataProviderCollection.php:77
‪TYPO3\CMS\Backend\View\BackendLayoutView\addItems
‪array addItems($items, $iArray)
Definition: BackendLayoutView.php:313
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:38
‪TYPO3\CMS\Backend\View\BackendLayoutView
Definition: BackendLayoutView.php:37
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪TYPO3\CMS\Core\SingletonInterface
Definition: SingletonInterface.php:22
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\View\BackendLayoutView\getDataProviderCollection
‪DataProviderCollection getDataProviderCollection()
Definition: BackendLayoutView.php:87
‪TYPO3\CMS\Backend\View\BackendLayout\BackendLayout
Definition: BackendLayout.php:25
‪TYPO3\CMS\Backend\View\BackendLayoutView\getColPosListItemsParsed
‪array getColPosListItemsParsed($id)
Definition: BackendLayoutView.php:281
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Backend\View\BackendLayoutView\addBackendLayoutItems
‪addBackendLayoutItems(array &$parameters)
Definition: BackendLayoutView.php:105
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderContext\setData
‪DataProviderContext setData(array $data)
Definition: DataProviderContext.php:111
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderCollection\getBackendLayout
‪BackendLayout null getBackendLayout($combinedIdentifier, $pageId)
Definition: DataProviderCollection.php:100
‪TYPO3\CMS\Backend\View\BackendLayoutView\getSelectedCombinedIdentifier
‪bool string getSelectedCombinedIdentifier($pageId)
Definition: BackendLayoutView.php:188
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderContext
Definition: DataProviderContext.php:24
‪TYPO3\CMS\Backend\View\BackendLayoutView\getBackendLayoutForPage
‪BackendLayout getBackendLayoutForPage(int $pageId)
Definition: BackendLayoutView.php:355
‪TYPO3\CMS\Backend\View\BackendLayout\DefaultDataProvider
Definition: DefaultDataProvider.php:32
‪TYPO3\CMS\Backend\View\BackendLayoutView\$selectedCombinedIdentifier
‪array $selectedCombinedIdentifier
Definition: BackendLayoutView.php:44