TYPO3 CMS  TYPO3_7-6
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 
20 
25 {
30 
35 
39  protected $selectedBackendLayout = [];
40 
44  public function __construct()
45  {
46  $this->initializeDataProviderCollection();
47  }
48 
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  $pageId = null;
145 
146  if (strpos($data['uid'], 'NEW') === 0) {
147  // negative uid_pid values of content elements indicate that the element has been inserted after an existing element
148  // so there is no pid to get the backendLayout for and we have to get that first
149  if ($data['pid'] < 0) {
150  $existingElement = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
151  'pid', $tableName, 'uid=' . abs($data['pid'])
152  );
153  if ($existingElement !== null) {
154  $pageId = $existingElement['pid'];
155  }
156  } else {
157  $pageId = $data['pid'];
158  }
159  } elseif ($tableName === 'pages') {
160  $pageId = $data['uid'];
161  } else {
162  $pageId = $data['pid'];
163  }
164 
165  return $pageId;
166  }
167 
174  public function getSelectedCombinedIdentifier($pageId)
175  {
176  if (!isset($this->selectedCombinedIdentifier[$pageId])) {
177  $page = $this->getPage($pageId);
178  $this->selectedCombinedIdentifier[$pageId] = (string)$page['backend_layout'];
179 
180  if ($this->selectedCombinedIdentifier[$pageId] === '-1') {
181  // If it is set to "none" - don't use any
182  $this->selectedCombinedIdentifier[$pageId] = false;
183  } elseif ($this->selectedCombinedIdentifier[$pageId] === '' || $this->selectedCombinedIdentifier[$pageId] === '0') {
184  // If it not set check the root-line for a layout on next level and use this
185  // (root-line starts with current page and has page "0" at the end)
186  $rootLine = $this->getRootLine($pageId);
187  // Remove first and last element (current and root page)
188  array_shift($rootLine);
189  array_pop($rootLine);
190  foreach ($rootLine as $rootLinePage) {
191  $this->selectedCombinedIdentifier[$pageId] = (string)$rootLinePage['backend_layout_next_level'];
192  if ($this->selectedCombinedIdentifier[$pageId] === '-1') {
193  // If layout for "next level" is set to "none" - don't use any and stop searching
194  $this->selectedCombinedIdentifier[$pageId] = false;
195  break;
196  } elseif ($this->selectedCombinedIdentifier[$pageId] !== '' && $this->selectedCombinedIdentifier[$pageId] !== '0') {
197  // Stop searching if a layout for "next level" is set
198  break;
199  }
200  }
201  }
202  }
203  // If it is set to a positive value use this
204  return $this->selectedCombinedIdentifier[$pageId];
205  }
206 
213  protected function getIdentifiersToBeExcluded(array $pageTSconfig)
214  {
215  $identifiersToBeExcluded = [];
216 
217  if (ArrayUtility::isValidPath($pageTSconfig, 'options./backendLayout./exclude')) {
218  $identifiersToBeExcluded = GeneralUtility::trimExplode(
219  ',',
220  ArrayUtility::getValueByPath($pageTSconfig, 'options./backendLayout./exclude'),
221  true
222  );
223  }
224 
225  return $identifiersToBeExcluded;
226  }
227 
236  public function colPosListItemProcFunc(array $parameters)
237  {
238  $pageId = $this->determinePageId($parameters['table'], $parameters['row']);
239 
240  if ($pageId !== null) {
241  $parameters['items'] = $this->addColPosListLayoutItems($pageId, $parameters['items']);
242  }
243  }
244 
252  protected function addColPosListLayoutItems($pageId, $items)
253  {
254  $layout = $this->getSelectedBackendLayout($pageId);
255  if ($layout && $layout['__items']) {
256  $items = $layout['__items'];
257  }
258  return $items;
259  }
260 
267  public function getColPosListItemsParsed($id)
268  {
269  $tsConfig = BackendUtility::getModTSconfig($id, 'TCEFORM.tt_content.colPos');
270  $tcaConfig = $GLOBALS['TCA']['tt_content']['columns']['colPos']['config'];
271  $tcaItems = $tcaConfig['items'];
272  $tcaItems = $this->addItems($tcaItems, $tsConfig['properties']['addItems.']);
273  if (isset($tcaConfig['itemsProcFunc']) && $tcaConfig['itemsProcFunc']) {
274  $tcaItems = $this->addColPosListLayoutItems($id, $tcaItems);
275  }
276  foreach (GeneralUtility::trimExplode(',', $tsConfig['properties']['removeItems'], true) as $removeId) {
277  foreach ($tcaItems as $key => $item) {
278  if ($item[1] == $removeId) {
279  unset($tcaItems[$key]);
280  }
281  }
282  }
283  return $tcaItems;
284  }
285 
297  protected function addItems($items, $iArray)
298  {
299  $languageService = static::getLanguageService();
300  if (is_array($iArray)) {
301  foreach ($iArray as $value => $label) {
302  // if the label is an array (that means it is a subelement
303  // like "34.icon = mylabel.png", skip it (see its usage below)
304  if (is_array($label)) {
305  continue;
306  }
307  // check if the value "34 = mylabel" also has a "34.icon = myimage.png"
308  if (isset($iArray[$value . '.']) && $iArray[$value . '.']['icon']) {
309  $icon = $iArray[$value . '.']['icon'];
310  } else {
311  $icon = '';
312  }
313  $items[] = [$languageService->sL($label), $value, $icon];
314  }
315  }
316  return $items;
317  }
318 
325  public function getSelectedBackendLayout($pageId)
326  {
327  if (isset($this->selectedBackendLayout[$pageId])) {
328  return $this->selectedBackendLayout[$pageId];
329  }
330  $backendLayoutData = null;
331 
333  // If no backend layout is selected, use default
334  if (empty($selectedCombinedIdentifier)) {
335  $selectedCombinedIdentifier = 'default';
336  }
337 
338  $backendLayout = $this->getDataProviderCollection()->getBackendLayout($selectedCombinedIdentifier, $pageId);
339  // If backend layout is not found available anymore, use default
340  if (is_null($backendLayout)) {
341  $selectedCombinedIdentifier = 'default';
342  $backendLayout = $this->getDataProviderCollection()->getBackendLayout($selectedCombinedIdentifier, $pageId);
343  }
344 
345  if (!empty($backendLayout)) {
347  $parser = GeneralUtility::makeInstance(\TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::class);
349  $conditionMatcher = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher::class);
350  $parser->parse($parser->checkIncludeLines($backendLayout->getConfiguration()), $conditionMatcher);
351 
352  $backendLayoutData = [];
353  $backendLayoutData['config'] = $backendLayout->getConfiguration();
354  $backendLayoutData['__config'] = $parser->setup;
355  $backendLayoutData['__items'] = [];
356  $backendLayoutData['__colPosList'] = [];
357 
358  // create items and colPosList
359  if (!empty($backendLayoutData['__config']['backend_layout.']['rows.'])) {
360  foreach ($backendLayoutData['__config']['backend_layout.']['rows.'] as $row) {
361  if (!empty($row['columns.'])) {
362  foreach ($row['columns.'] as $column) {
363  if (!isset($column['colPos'])) {
364  continue;
365  }
366  $backendLayoutData['__items'][] = [
367  GeneralUtility::isFirstPartOfStr($column['name'], 'LLL:') ? $this->getLanguageService()->sL($column['name']) : $column['name'],
368  $column['colPos'],
369  null
370  ];
371  $backendLayoutData['__colPosList'][] = $column['colPos'];
372  }
373  }
374  }
375  }
376 
377  $this->selectedBackendLayout[$pageId] = $backendLayoutData;
378  }
379 
380  return $backendLayoutData;
381  }
382 
389  public static function getDefaultColumnLayout()
390  {
391  return '
392  backend_layout {
393  colCount = 4
394  rowCount = 1
395  rows {
396  1 {
397  columns {
398  1 {
399  name = LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.0
400  colPos = 1
401  }
402  2 {
403  name = LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.1
404  colPos = 0
405  }
406  3 {
407  name = LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.2
408  colPos = 2
409  }
410  4 {
411  name = LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.3
412  colPos = 3
413  }
414  }
415  }
416  }
417  }
418  ';
419  }
420 
427  protected function getPage($pageId)
428  {
429  $page = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
430  'uid, pid, backend_layout',
431  'pages',
432  'uid=' . (int)$pageId
433  );
434  BackendUtility::workspaceOL('pages', $page);
435  return $page;
436  }
437 
444  protected function getRootLine($pageId)
445  {
446  return BackendUtility::BEgetRootLine($pageId, '', true);
447  }
448 
452  protected function createDataProviderContext()
453  {
454  return GeneralUtility::makeInstance(BackendLayout\DataProviderContext::class);
455  }
456 
460  protected function getDatabaseConnection()
461  {
462  return $GLOBALS['TYPO3_DB'];
463  }
464 
468  protected function getLanguageService()
469  {
470  return $GLOBALS['LANG'];
471  }
472 }
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 isValidPath(array $array, $path, $delimiter='/')
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']