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 16namespace TYPO3\CMS\Backend\View\BackendLayout; 17 18use TYPO3\CMS\Backend\Utility\BackendUtility; 19use TYPO3\CMS\Backend\View\BackendLayoutView; 20use TYPO3\CMS\Core\Context\Context; 21use TYPO3\CMS\Core\Database\ConnectionPool; 22use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder; 23use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction; 24use TYPO3\CMS\Core\Resource\FileRepository; 25use TYPO3\CMS\Core\Utility\GeneralUtility; 26 27/** 28 * Backend layout data provider class 29 */ 30class DefaultDataProvider implements DataProviderInterface 31{ 32 33 /** 34 * @var string 35 * Table name for backend_layouts 36 */ 37 protected $tableName = 'backend_layout'; 38 39 /** 40 * Adds backend layouts to the given backend layout collection. 41 * The default backend layout ('default_default') is not added 42 * since it's the default fallback if nothing is specified. 43 * 44 * @param DataProviderContext $dataProviderContext 45 * @param BackendLayoutCollection $backendLayoutCollection 46 */ 47 public function addBackendLayouts( 48 DataProviderContext $dataProviderContext, 49 BackendLayoutCollection $backendLayoutCollection 50 ) { 51 $layoutData = $this->getLayoutData( 52 $dataProviderContext->getFieldName(), 53 $dataProviderContext->getPageTsConfig(), 54 $dataProviderContext->getPageId() 55 ); 56 57 foreach ($layoutData as $data) { 58 $backendLayout = $this->createBackendLayout($data); 59 $backendLayoutCollection->add($backendLayout); 60 } 61 } 62 63 /** 64 * Gets a backend layout by (regular) identifier. 65 * 66 * @param string|int $identifier 67 * @param int $pageId 68 * @return BackendLayout|null 69 */ 70 public function getBackendLayout($identifier, $pageId) 71 { 72 $backendLayout = null; 73 74 if ((string)$identifier === 'default') { 75 return $this->createDefaultBackendLayout(); 76 } 77 78 $data = BackendUtility::getRecordWSOL($this->tableName, (int)$identifier); 79 80 if (is_array($data)) { 81 $backendLayout = $this->createBackendLayout($data); 82 } 83 84 return $backendLayout; 85 } 86 87 /** 88 * Creates a backend layout with the default configuration. 89 * 90 * @return BackendLayout 91 */ 92 protected function createDefaultBackendLayout() 93 { 94 return BackendLayout::create( 95 'default', 96 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.backend_layout.default', 97 BackendLayoutView::getDefaultColumnLayout() 98 ); 99 } 100 101 /** 102 * Creates a new backend layout using the given record data. 103 * 104 * @param array $data 105 * @return BackendLayout 106 */ 107 protected function createBackendLayout(array $data) 108 { 109 $backendLayout = BackendLayout::create($data['uid'], $data['title'], $data['config']); 110 $backendLayout->setIconPath($this->getIconPath($data)); 111 $backendLayout->setData($data); 112 return $backendLayout; 113 } 114 115 /** 116 * Resolves the icon from the database record 117 * 118 * @param array $icon 119 * @return string 120 */ 121 protected function getIconPath(array $icon) 122 { 123 $fileRepository = GeneralUtility::makeInstance(FileRepository::class); 124 $references = $fileRepository->findByRelation($this->tableName, 'icon', $icon['uid']); 125 if (!empty($references)) { 126 $icon = reset($references); 127 return $icon->getPublicUrl(); 128 } 129 return ''; 130 } 131 132 /** 133 * Get all layouts from the core's default data provider. 134 * 135 * @param string $fieldName the name of the field the layouts are provided for (either backend_layout or backend_layout_next_level) 136 * @param array $pageTsConfig PageTSconfig of the given page 137 * @param int $pageUid the ID of the page wea re getting the layouts for 138 * @return array $layouts A collection of layout data of the registered provider 139 */ 140 protected function getLayoutData($fieldName, array $pageTsConfig, $pageUid) 141 { 142 $storagePid = $this->getStoragePid($pageTsConfig); 143 $pageTsConfigId = $this->getPageTSconfigIds($pageTsConfig); 144 145 // Add layout records 146 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) 147 ->getQueryBuilderForTable($this->tableName); 148 $queryBuilder->getRestrictions() 149 ->add( 150 GeneralUtility::makeInstance( 151 WorkspaceRestriction::class, 152 GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('workspace', 'id') 153 ) 154 ); 155 $queryBuilder 156 ->select('*') 157 ->from($this->tableName) 158 ->where( 159 $queryBuilder->expr()->orX( 160 $queryBuilder->expr()->andX( 161 $queryBuilder->expr()->comparison( 162 $queryBuilder->createNamedParameter($pageTsConfigId[$fieldName], \PDO::PARAM_INT), 163 ExpressionBuilder::EQ, 164 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) 165 ), 166 $queryBuilder->expr()->comparison( 167 $queryBuilder->createNamedParameter($storagePid, \PDO::PARAM_INT), 168 ExpressionBuilder::EQ, 169 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) 170 ) 171 ), 172 $queryBuilder->expr()->orX( 173 $queryBuilder->expr()->eq( 174 'backend_layout.pid', 175 $queryBuilder->createNamedParameter($pageTsConfigId[$fieldName], \PDO::PARAM_INT) 176 ), 177 $queryBuilder->expr()->eq( 178 'backend_layout.pid', 179 $queryBuilder->createNamedParameter($storagePid, \PDO::PARAM_INT) 180 ) 181 ), 182 $queryBuilder->expr()->andX( 183 $queryBuilder->expr()->comparison( 184 $queryBuilder->createNamedParameter($pageTsConfigId[$fieldName], \PDO::PARAM_INT), 185 ExpressionBuilder::EQ, 186 $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT) 187 ), 188 $queryBuilder->expr()->eq( 189 'backend_layout.pid', 190 $queryBuilder->createNamedParameter($pageUid, \PDO::PARAM_INT) 191 ) 192 ) 193 ) 194 ); 195 196 if (!empty($GLOBALS['TCA'][$this->tableName]['ctrl']['sortby'])) { 197 $queryBuilder->orderBy($GLOBALS['TCA'][$this->tableName]['ctrl']['sortby']); 198 } 199 200 $statement = $queryBuilder->execute(); 201 202 $results = []; 203 while ($record = $statement->fetch()) { 204 BackendUtility::workspaceOL($this->tableName, $record); 205 if (is_array($record)) { 206 $results[$record['t3ver_oid'] ?: $record['uid']] = $record; 207 } 208 } 209 210 return $results; 211 } 212 213 /** 214 * Returns the storage PID from TCEFORM. 215 * 216 * @param array $pageTsConfig 217 * @return int 218 */ 219 protected function getStoragePid(array $pageTsConfig) 220 { 221 $storagePid = 0; 222 223 if (!empty($pageTsConfig['TCEFORM.']['pages.']['_STORAGE_PID'])) { 224 $storagePid = (int)$pageTsConfig['TCEFORM.']['pages.']['_STORAGE_PID']; 225 } 226 227 return $storagePid; 228 } 229 230 /** 231 * Returns the page TSconfig from TCEFORM. 232 * 233 * @param array $pageTsConfig 234 * @return array 235 */ 236 protected function getPageTSconfigIds(array $pageTsConfig) 237 { 238 $pageTsConfigIds = [ 239 'backend_layout' => 0, 240 'backend_layout_next_level' => 0, 241 ]; 242 243 if (!empty($pageTsConfig['TCEFORM.']['pages.']['backend_layout.']['PAGE_TSCONFIG_ID'])) { 244 $pageTsConfigIds['backend_layout'] = (int)$pageTsConfig['TCEFORM.']['pages.']['backend_layout.']['PAGE_TSCONFIG_ID']; 245 } 246 247 if (!empty($pageTsConfig['TCEFORM.']['pages.']['backend_layout_next_level.']['PAGE_TSCONFIG_ID'])) { 248 $pageTsConfigIds['backend_layout_next_level'] = (int)$pageTsConfig['TCEFORM.']['pages.']['backend_layout_next_level.']['PAGE_TSCONFIG_ID']; 249 } 250 251 return $pageTsConfigIds; 252 } 253} 254