‪TYPO3CMS  ‪main
BackendLayoutView.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 
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
31 
37 {
38  protected array ‪$selectedCombinedIdentifier = [];
39  protected array ‪$selectedBackendLayout = [];
40 
44  public function ‪__construct(
45  private readonly ‪DataProviderCollection $dataProviderCollection,
46  private readonly ‪TypoScriptStringFactory $typoScriptStringFactory,
47  private readonly ‪PageLayoutResolver $pageLayoutResolver,
48  ) {
49  $this->dataProviderCollection->add('default', DefaultDataProvider::class);
50  foreach ((array)(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider'] ?? []) as ‪$identifier => $className) {
51  $this->dataProviderCollection->add(‪$identifier, $className);
52  }
53  }
54 
67  public function ‪addBackendLayoutItems(array &$parameters)
68  {
69  $pageId = $this->‪determinePageId($parameters['table'], $parameters['row']) ?: 0;
70  $pageTsConfig = BackendUtility::getPagesTSconfig($pageId);
71  $identifiersToBeExcluded = $this->‪getIdentifiersToBeExcluded($pageTsConfig);
72 
73  $dataProviderContext = GeneralUtility::makeInstance(DataProviderContext::class);
74  $dataProviderContext
75  ->setPageId($pageId)
76  ->setData($parameters['row'])
77  ->setTableName($parameters['table'])
78  ->setFieldName($parameters['field'])
79  ->setPageTsConfig($pageTsConfig);
80 
81  $backendLayoutCollections = $this->dataProviderCollection->getBackendLayoutCollections($dataProviderContext);
82  foreach ($backendLayoutCollections as $backendLayoutCollection) {
83  $combinedIdentifierPrefix = '';
84  if ($backendLayoutCollection->getIdentifier() !== 'default') {
85  $combinedIdentifierPrefix = $backendLayoutCollection->getIdentifier() . '__';
86  }
87 
88  foreach ($backendLayoutCollection->getAll() as $backendLayout) {
89  $combinedIdentifier = $combinedIdentifierPrefix . $backendLayout->getIdentifier();
90 
91  if (in_array($combinedIdentifier, $identifiersToBeExcluded, true)) {
92  continue;
93  }
94 
95  $parameters['items'][] = [
96  'label' => $backendLayout->getTitle(),
97  'value' => $combinedIdentifier,
98  'icon' => $backendLayout->getIconPath(),
99  ];
100  }
101  }
102  }
103 
109  protected function ‪determinePageId(string $tableName, array $data): int|false
110  {
111  if ($data === []) {
112  return false;
113  }
114 
115  if (str_starts_with((string)$data['uid'], 'NEW')) {
116  // negative uid_pid values of content elements indicate that the element
117  // has been inserted after an existing element so there is no pid to get
118  // the backendLayout for and we have to get that first
119  if ($data['pid'] < 0) {
120  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
121  ->getQueryBuilderForTable($tableName);
122  $queryBuilder->getRestrictions()
123  ->removeAll();
124  $pageId = $queryBuilder
125  ->select('pid')
126  ->from($tableName)
127  ->where(
128  $queryBuilder->expr()->eq(
129  'uid',
130  $queryBuilder->createNamedParameter(abs($data['pid']), ‪Connection::PARAM_INT)
131  )
132  )
133  ->executeQuery()
134  ->fetchOne();
135  } else {
136  $pageId = $data['pid'];
137  }
138  } elseif ($tableName === 'pages') {
139  $pageId = $data['uid'];
140  } else {
141  $pageId = $data['pid'];
142  }
143 
144  return (int)$pageId;
145  }
146 
153  public function ‪getSelectedCombinedIdentifier(int $pageId): string|false
154  {
155  if (!isset($this->selectedCombinedIdentifier[$pageId])) {
156  // If it not set check the root-line for a layout on next level and use this
157  // (root-line starts with current page and has page "0" at the end)
158  $rootLine = BackendUtility::BEgetRootLine($pageId, '', true);
159  // Use first element as current page,
160  $page = reset($rootLine);
161  // and remove last element (root page / pid=0)
162  array_pop($rootLine);
163  $selectedLayout = $this->pageLayoutResolver->getLayoutIdentifierForPage($page, $rootLine);
164  if ($selectedLayout === 'none') {
165  // If it is set to "none" - don't use any
166  $selectedLayout = false;
167  } elseif ($selectedLayout === 'default') {
168  $selectedLayout = '0';
169  }
170  $this->selectedCombinedIdentifier[$pageId] = $selectedLayout;
171  }
172  // If it is set to a positive value use this
173  return $this->selectedCombinedIdentifier[$pageId];
174  }
175 
179  protected function ‪getIdentifiersToBeExcluded(array $pageTSconfig): array
180  {
181  if (isset($pageTSconfig['options.']['backendLayout.']['exclude'])) {
183  ',',
184  $pageTSconfig['options.']['backendLayout.']['exclude'],
185  true
186  );
187  }
188  return [];
189  }
190 
196  public function ‪colPosListItemProcFunc(array &$parameters): void
197  {
198  $pageId = $this->‪determinePageId($parameters['table'], $parameters['row']);
199 
200  if ($pageId !== false) {
201  $parameters['items'] = $this->‪addColPosListLayoutItems($pageId, $parameters['items']);
202  }
203  }
204 
208  protected function ‪addColPosListLayoutItems(int $pageId, array $items): array
209  {
210  $layout = $this->‪getSelectedBackendLayout($pageId);
211  if ($layout && !empty($layout['__items'])) {
212  $items = $layout['__items'];
213  }
214  return $items;
215  }
216 
220  public function ‪getSelectedBackendLayout(int $pageId): ?array
221  {
222  return $this->‪getBackendLayoutForPage($pageId)?->getStructure();
223  }
224 
228  public function ‪getBackendLayoutForPage(int $pageId): ?‪BackendLayout
229  {
230  if (isset($this->selectedBackendLayout[$pageId])) {
231  return $this->selectedBackendLayout[$pageId];
232  }
234  // If no backend layout is selected, use default
235  if (empty(‪$selectedCombinedIdentifier)) {
236  ‪$selectedCombinedIdentifier = 'default';
237  }
238  $backendLayout = $this->dataProviderCollection->getBackendLayout(‪$selectedCombinedIdentifier, $pageId);
239  // If backend layout is not found available anymore, use default
240  if ($backendLayout === null) {
241  $backendLayout = $this->dataProviderCollection->getBackendLayout('default', $pageId);
242  }
243 
244  if ($backendLayout !== null) {
245  $this->selectedBackendLayout[$pageId] = $backendLayout;
246  }
247  return $backendLayout;
248  }
249 
253  public function ‪parseStructure(‪BackendLayout $backendLayout): array
254  {
255  $typoScriptTree = $this->typoScriptStringFactory->parseFromStringWithIncludes('backend-layout', $backendLayout->‪getConfiguration());
256 
257  $backendLayoutData = [];
258  $backendLayoutData['config'] = $backendLayout->‪getConfiguration();
259  $backendLayoutData['__config'] = $typoScriptTree->toArray();
260  $backendLayoutData['__items'] = [];
261  $backendLayoutData['__colPosList'] = [];
262  $backendLayoutData['usedColumns'] = [];
263  $backendLayoutData['colCount'] = (int)($backendLayoutData['__config']['backend_layout.']['colCount'] ?? 0);
264  $backendLayoutData['rowCount'] = (int)($backendLayoutData['__config']['backend_layout.']['rowCount'] ?? 0);
265 
266  // create items and colPosList
267  if (!empty($backendLayoutData['__config']['backend_layout.']['rows.'])) {
268  $rows = $backendLayoutData['__config']['backend_layout.']['rows.'];
269  ksort($rows);
270  foreach ($rows as $row) {
271  if (!empty($row['columns.'])) {
272  foreach ($row['columns.'] as $column) {
273  if (!isset($column['colPos'])) {
274  continue;
275  }
276  $backendLayoutData['__items'][] = [
277  'label' => $column['name'],
278  'value' => $column['colPos'],
279  'icon' => null,
280  ];
281  $backendLayoutData['__colPosList'][] = $column['colPos'];
282  $backendLayoutData['usedColumns'][(int)$column['colPos']] = $column['name'];
283  }
284  }
285  }
286  }
287  return $backendLayoutData;
288  }
289 
293  public static function ‪getDefaultColumnLayout(): string
294  {
295  return '
296  backend_layout {
297  colCount = 1
298  rowCount = 1
299  rows {
300  1 {
301  columns {
302  1 {
303  name = LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.1
304  colPos = 0
305  }
306  }
307  }
308  }
309  }
310  ';
311  }
312 }
‪TYPO3\CMS\Backend\View\BackendLayoutView\__construct
‪__construct(private readonly DataProviderCollection $dataProviderCollection, private readonly TypoScriptStringFactory $typoScriptStringFactory, private readonly PageLayoutResolver $pageLayoutResolver,)
Definition: BackendLayoutView.php:44
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:52
‪TYPO3\CMS\Backend\View\BackendLayoutView\colPosListItemProcFunc
‪colPosListItemProcFunc(array &$parameters)
Definition: BackendLayoutView.php:196
‪TYPO3\CMS\Backend\View
Definition: AuthenticationStyleInformation.php:18
‪TYPO3\CMS\Backend\View\BackendLayoutView\getSelectedBackendLayout
‪getSelectedBackendLayout(int $pageId)
Definition: BackendLayoutView.php:220
‪TYPO3\CMS\Backend\View\BackendLayoutView\$selectedBackendLayout
‪array $selectedBackendLayout
Definition: BackendLayoutView.php:39
‪TYPO3\CMS\Core\Page\PageLayoutResolver
Definition: PageLayoutResolver.php:42
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderCollection
Definition: DataProviderCollection.php:27
‪TYPO3\CMS\Backend\View\BackendLayoutView\determinePageId
‪int false determinePageId(string $tableName, array $data)
Definition: BackendLayoutView.php:109
‪TYPO3\CMS\Backend\View\BackendLayoutView\getDefaultColumnLayout
‪static getDefaultColumnLayout()
Definition: BackendLayoutView.php:293
‪TYPO3\CMS\Backend\View\BackendLayoutView\getBackendLayoutForPage
‪getBackendLayoutForPage(int $pageId)
Definition: BackendLayoutView.php:228
‪TYPO3\CMS\Backend\View\BackendLayoutView\parseStructure
‪parseStructure(BackendLayout $backendLayout)
Definition: BackendLayoutView.php:253
‪TYPO3\CMS\Backend\View\BackendLayout\BackendLayout\getConfiguration
‪getConfiguration()
Definition: BackendLayout.php:109
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪TYPO3\CMS\Backend\View\BackendLayoutView
Definition: BackendLayoutView.php:37
‪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\getIdentifiersToBeExcluded
‪getIdentifiersToBeExcluded(array $pageTSconfig)
Definition: BackendLayoutView.php:179
‪TYPO3\CMS\Backend\View\BackendLayout\BackendLayout
Definition: BackendLayout.php:27
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Backend\View\BackendLayoutView\addColPosListLayoutItems
‪addColPosListLayoutItems(int $pageId, array $items)
Definition: BackendLayoutView.php:208
‪TYPO3\CMS\Backend\View\BackendLayoutView\getSelectedCombinedIdentifier
‪false string getSelectedCombinedIdentifier(int $pageId)
Definition: BackendLayoutView.php:153
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Backend\View\BackendLayoutView\addBackendLayoutItems
‪addBackendLayoutItems(array &$parameters)
Definition: BackendLayoutView.php:67
‪TYPO3\CMS\Core\TypoScript\TypoScriptStringFactory
Definition: TypoScriptStringFactory.php:37
‪TYPO3\CMS\Backend\View\BackendLayout\DataProviderContext
Definition: DataProviderContext.php:26
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37
‪TYPO3\CMS\Backend\View\BackendLayout\DefaultDataProvider
Definition: DefaultDataProvider.php:34
‪TYPO3\CMS\Backend\View\BackendLayoutView\$selectedCombinedIdentifier
‪array $selectedCombinedIdentifier
Definition: BackendLayoutView.php:38