TYPO3 CMS  TYPO3_8-7
BackendLayoutView.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\View;
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 
22 
27 {
32 
37 
41  protected $selectedBackendLayout = [];
42 
46  public function __construct()
47  {
48  $this->initializeDataProviderCollection();
49  }
50 
54  protected function initializeDataProviderCollection()
55  {
58  BackendLayout\DataProviderCollection::class
59  );
60 
62  'default',
63  \TYPO3\CMS\Backend\View\BackendLayout\DefaultDataProvider::class
64  );
65 
66  if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider'])) {
67  $dataProviders = (array)$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider'];
68  foreach ($dataProviders as $identifier => $className) {
69  $dataProviderCollection->add($identifier, $className);
70  }
71  }
72 
74  }
75 
79  public function setDataProviderCollection(BackendLayout\DataProviderCollection $dataProviderCollection)
80  {
81  $this->dataProviderCollection = $dataProviderCollection;
82  }
83 
87  public function getDataProviderCollection()
88  {
90  }
91 
99  public function addBackendLayoutItems(array $parameters)
100  {
101  $pageId = $this->determinePageId($parameters['table'], $parameters['row']);
102  $pageTsConfig = (array)BackendUtility::getPagesTSconfig($pageId);
103  $identifiersToBeExcluded = $this->getIdentifiersToBeExcluded($pageTsConfig);
104 
105  $dataProviderContext = $this->createDataProviderContext()
106  ->setPageId($pageId)
107  ->setData($parameters['row'])
108  ->setTableName($parameters['table'])
109  ->setFieldName($parameters['field'])
110  ->setPageTsConfig($pageTsConfig);
111 
112  $backendLayoutCollections = $this->getDataProviderCollection()->getBackendLayoutCollections($dataProviderContext);
113  foreach ($backendLayoutCollections as $backendLayoutCollection) {
114  $combinedIdentifierPrefix = '';
115  if ($backendLayoutCollection->getIdentifier() !== 'default') {
116  $combinedIdentifierPrefix = $backendLayoutCollection->getIdentifier() . '__';
117  }
118 
119  foreach ($backendLayoutCollection->getAll() as $backendLayout) {
120  $combinedIdentifier = $combinedIdentifierPrefix . $backendLayout->getIdentifier();
121 
122  if (in_array($combinedIdentifier, $identifiersToBeExcluded, true)) {
123  continue;
124  }
125 
126  $parameters['items'][] = [
127  $this->getLanguageService()->sL($backendLayout->getTitle()),
128  $combinedIdentifier,
129  $backendLayout->getIconPath(),
130  ];
131  }
132  }
133  }
134 
142  protected function determinePageId($tableName, array $data)
143  {
144  if (strpos($data['uid'], 'NEW') === 0) {
145  // negative uid_pid values of content elements indicate that the element
146  // has been inserted after an existing element so there is no pid to get
147  // the backendLayout for and we have to get that first
148  if ($data['pid'] < 0) {
149  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
150  ->getQueryBuilderForTable($tableName);
151  $queryBuilder->getRestrictions()
152  ->removeAll();
153  $pageId = $queryBuilder
154  ->select('pid')
155  ->from($tableName)
156  ->where(
157  $queryBuilder->expr()->eq(
158  'uid',
159  $queryBuilder->createNamedParameter(abs($data['pid']), \PDO::PARAM_INT)
160  )
161  )
162  ->execute()
163  ->fetchColumn();
164  } else {
165  $pageId = $data['pid'];
166  }
167  } elseif ($tableName === 'pages') {
168  $pageId = $data['uid'];
169  } else {
170  $pageId = $data['pid'];
171  }
172 
173  return $pageId;
174  }
175 
182  public function getSelectedCombinedIdentifier($pageId)
183  {
184  if (!isset($this->selectedCombinedIdentifier[$pageId])) {
185  $page = $this->getPage($pageId);
186  $this->selectedCombinedIdentifier[$pageId] = (string)$page['backend_layout'];
187 
188  if ($this->selectedCombinedIdentifier[$pageId] === '-1') {
189  // If it is set to "none" - don't use any
190  $this->selectedCombinedIdentifier[$pageId] = false;
191  } elseif ($this->selectedCombinedIdentifier[$pageId] === '' || $this->selectedCombinedIdentifier[$pageId] === '0') {
192  // If it not set check the root-line for a layout on next level and use this
193  // (root-line starts with current page and has page "0" at the end)
194  $rootLine = $this->getRootLine($pageId);
195  // Remove first and last element (current and root page)
196  array_shift($rootLine);
197  array_pop($rootLine);
198  foreach ($rootLine as $rootLinePage) {
199  $this->selectedCombinedIdentifier[$pageId] = (string)$rootLinePage['backend_layout_next_level'];
200  if ($this->selectedCombinedIdentifier[$pageId] === '-1') {
201  // If layout for "next level" is set to "none" - don't use any and stop searching
202  $this->selectedCombinedIdentifier[$pageId] = false;
203  break;
204  }
205  if ($this->selectedCombinedIdentifier[$pageId] !== '' && $this->selectedCombinedIdentifier[$pageId] !== '0') {
206  // Stop searching if a layout for "next level" is set
207  break;
208  }
209  }
210  }
211  }
212  // If it is set to a positive value use this
213  return $this->selectedCombinedIdentifier[$pageId];
214  }
215 
222  protected function getIdentifiersToBeExcluded(array $pageTSconfig)
223  {
224  $identifiersToBeExcluded = [];
225 
226  if (ArrayUtility::isValidPath($pageTSconfig, 'options./backendLayout./exclude')) {
227  $identifiersToBeExcluded = GeneralUtility::trimExplode(
228  ',',
229  ArrayUtility::getValueByPath($pageTSconfig, 'options./backendLayout./exclude'),
230  true
231  );
232  }
233 
234  return $identifiersToBeExcluded;
235  }
236 
244  public function colPosListItemProcFunc(array $parameters)
245  {
246  $pageId = $this->determinePageId($parameters['table'], $parameters['row']);
247 
248  if ($pageId !== false) {
249  $parameters['items'] = $this->addColPosListLayoutItems($pageId, $parameters['items']);
250  }
251  }
252 
260  protected function addColPosListLayoutItems($pageId, $items)
261  {
262  $layout = $this->getSelectedBackendLayout($pageId);
263  if ($layout && $layout['__items']) {
264  $items = $layout['__items'];
265  }
266  return $items;
267  }
268 
275  public function getColPosListItemsParsed($id)
276  {
277  $tsConfig = BackendUtility::getModTSconfig($id, 'TCEFORM.tt_content.colPos');
278  $tcaConfig = $GLOBALS['TCA']['tt_content']['columns']['colPos']['config'];
279  $tcaItems = $tcaConfig['items'];
280  $tcaItems = $this->addItems($tcaItems, $tsConfig['properties']['addItems.']);
281  if (isset($tcaConfig['itemsProcFunc']) && $tcaConfig['itemsProcFunc']) {
282  $tcaItems = $this->addColPosListLayoutItems($id, $tcaItems);
283  }
284  foreach (GeneralUtility::trimExplode(',', $tsConfig['properties']['removeItems'], true) as $removeId) {
285  foreach ($tcaItems as $key => $item) {
286  if ($item[1] == $removeId) {
287  unset($tcaItems[$key]);
288  }
289  }
290  }
291  return $tcaItems;
292  }
293 
305  protected function addItems($items, $iArray)
306  {
307  $languageService = static::getLanguageService();
308  if (is_array($iArray)) {
309  foreach ($iArray as $value => $label) {
310  // if the label is an array (that means it is a subelement
311  // like "34.icon = mylabel.png", skip it (see its usage below)
312  if (is_array($label)) {
313  continue;
314  }
315  // check if the value "34 = mylabel" also has a "34.icon = myimage.png"
316  if (isset($iArray[$value . '.']) && $iArray[$value . '.']['icon']) {
317  $icon = $iArray[$value . '.']['icon'];
318  } else {
319  $icon = '';
320  }
321  $items[] = [$languageService->sL($label), $value, $icon];
322  }
323  }
324  return $items;
325  }
326 
333  public function getSelectedBackendLayout($pageId)
334  {
335  if (isset($this->selectedBackendLayout[$pageId])) {
336  return $this->selectedBackendLayout[$pageId];
337  }
338  $backendLayoutData = null;
339 
341  // If no backend layout is selected, use default
342  if (empty($selectedCombinedIdentifier)) {
343  $selectedCombinedIdentifier = 'default';
344  }
345 
346  $backendLayout = $this->getDataProviderCollection()->getBackendLayout($selectedCombinedIdentifier, $pageId);
347  // If backend layout is not found available anymore, use default
348  if (is_null($backendLayout)) {
349  $selectedCombinedIdentifier = 'default';
350  $backendLayout = $this->getDataProviderCollection()->getBackendLayout($selectedCombinedIdentifier, $pageId);
351  }
352 
353  if (!empty($backendLayout)) {
355  $parser = GeneralUtility::makeInstance(TypoScriptParser::class);
357  $conditionMatcher = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher::class);
358  $parser->parse(TypoScriptParser::checkIncludeLines($backendLayout->getConfiguration()), $conditionMatcher);
359 
360  $backendLayoutData = [];
361  $backendLayoutData['config'] = $backendLayout->getConfiguration();
362  $backendLayoutData['__config'] = $parser->setup;
363  $backendLayoutData['__items'] = [];
364  $backendLayoutData['__colPosList'] = [];
365 
366  // create items and colPosList
367  if (!empty($backendLayoutData['__config']['backend_layout.']['rows.'])) {
368  foreach ($backendLayoutData['__config']['backend_layout.']['rows.'] as $row) {
369  if (!empty($row['columns.'])) {
370  foreach ($row['columns.'] as $column) {
371  if (!isset($column['colPos'])) {
372  continue;
373  }
374  $backendLayoutData['__items'][] = [
375  $this->getColumnName($column),
376  $column['colPos'],
377  null
378  ];
379  $backendLayoutData['__colPosList'][] = $column['colPos'];
380  }
381  }
382  }
383  }
384 
385  $this->selectedBackendLayout[$pageId] = $backendLayoutData;
386  }
387 
388  return $backendLayoutData;
389  }
390 
397  public static function getDefaultColumnLayout()
398  {
399  return '
400  backend_layout {
401  colCount = 4
402  rowCount = 1
403  rows {
404  1 {
405  columns {
406  1 {
407  name = LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.0
408  colPos = 1
409  }
410  2 {
411  name = LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.1
412  colPos = 0
413  }
414  3 {
415  name = LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.2
416  colPos = 2
417  }
418  4 {
419  name = LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.3
420  colPos = 3
421  }
422  }
423  }
424  }
425  }
426  ';
427  }
428 
435  protected function getPage($pageId)
436  {
437  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
438  ->getQueryBuilderForTable('pages');
439  $queryBuilder->getRestrictions()
440  ->removeAll();
441  $page = $queryBuilder
442  ->select('uid', 'pid', 'backend_layout')
443  ->from('pages')
444  ->where(
445  $queryBuilder->expr()->eq(
446  'uid',
447  $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
448  )
449  )
450  ->execute()
451  ->fetch();
452  BackendUtility::workspaceOL('pages', $page);
453 
454  return $page;
455  }
456 
463  protected function getRootLine($pageId)
464  {
465  return BackendUtility::BEgetRootLine($pageId, '', true);
466  }
467 
471  protected function createDataProviderContext()
472  {
473  return GeneralUtility::makeInstance(BackendLayout\DataProviderContext::class);
474  }
475 
479  protected function getLanguageService()
480  {
481  return $GLOBALS['LANG'];
482  }
483 
490  protected function getColumnName($column)
491  {
492  $columnName = $column['name'];
493 
494  if (GeneralUtility::isFirstPartOfStr($columnName, 'LLL:')) {
495  $columnName = $this->getLanguageService()->sL($columnName);
496  }
497 
498  return $columnName;
499  }
500 }
static getPagesTSconfig($id, $rootLine=null, $returnPartArray=false)
static getValueByPath(array $array, $path, $delimiter='/')
static isFirstPartOfStr($str, $partStr)
static BEgetRootLine($uid, $clause='', $workspaceOL=false)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
setDataProviderCollection(BackendLayout\DataProviderCollection $dataProviderCollection)
static makeInstance($className,... $constructorArguments)
static isValidPath(array $array, $path, $delimiter='/')
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']