‪TYPO3CMS  ‪main
AbstractContentPagePositionMap.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 
36 {
40  public int ‪$cur_sys_language = 0;
41 
43 
45  {
46  $this->backendLayoutView = ‪$backendLayoutView;
47  }
48 
58  abstract protected function ‪insertPositionIcon(?array $row, int $colPos, int $pid): string;
59 
66  abstract protected function ‪getRecordHeader(array $row): string;
67 
74  public function ‪printContentElementColumns(int $pid): string
75  {
76  $lines = [];
77  $columnsConfiguration = $this->‪getColumnsConfiguration($pid);
78  foreach ($columnsConfiguration as $columnConfiguration) {
79  if ($columnConfiguration['isRestricted']) {
80  // Do not fetch records of restricted columns
81  continue;
82  }
83  $colPos = $columnConfiguration['colPos'];
84  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
85  $queryBuilder
86  ->getRestrictions()
87  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $this->‪getBackendUser()->workspace))
88  ->removeByType(HiddenRestriction::class)
89  ->removeByType(StartTimeRestriction::class)
90  ->removeByType(EndTimeRestriction::class);
91  $queryBuilder
92  ->select('*')
93  ->from('tt_content')
94  ->where(
95  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pid, ‪Connection::PARAM_INT)),
96  $queryBuilder->expr()->eq('colPos', $queryBuilder->createNamedParameter($colPos, ‪Connection::PARAM_INT))
97  )
98  ->orderBy('sorting');
99 
100  if ((string)$this->cur_sys_language !== '') {
101  $queryBuilder->andWhere(
102  $queryBuilder->expr()->eq(
103  'sys_language_uid',
104  $queryBuilder->createNamedParameter($this->cur_sys_language, ‪Connection::PARAM_INT)
105  )
106  );
107  }
108 
109  $res = $queryBuilder->executeQuery();
110  $lines[$colPos] = [
111  $this->‪insertPositionIcon(null, $colPos, $pid),
112  ];
113 
114  while ($row = $res->fetchAssociative()) {
115  BackendUtility::workspaceOL('tt_content', $row);
116  if (is_array($row)) {
117  $lines[$colPos][] = $this->‪getRecordHeader($row);
118  $lines[$colPos][] = $this->‪insertPositionIcon($row, $colPos, $pid);
119  }
120  }
121  }
122  return $this->‪printRecordMap($lines, $columnsConfiguration, $pid);
123  }
124 
133  protected function ‪printRecordMap(array $lines, array $tcaColumnsConfiguration, int $pid): string
134  {
135  $lang = $this->‪getLanguageService();
136  $hideRestrictedColumns = (bool)(BackendUtility::getPagesTSconfig($pid)['mod.']['web_layout.']['hideRestrictedCols'] ?? false);
137  $backendLayout = $this->backendLayoutView->getSelectedBackendLayout($pid);
138 
139  if (isset($backendLayout['__config']['backend_layout.'])) {
140  // Build position map based on the fetched backend layout
141  $colCount = (int)($backendLayout['__config']['backend_layout.']['colCount'] ?? 0);
142  $rowCount = (int)($backendLayout['__config']['backend_layout.']['rowCount'] ?? 0);
143 
144  // Cycle through rows
145  $tableRows = [];
146  for ($row = 1; $row <= $rowCount; $row++) {
147  $rowConfig = $backendLayout['__config']['backend_layout.']['rows.'][$row . '.'] ?? null;
148  if (!$rowConfig) {
149  // Skip empty rows
150  continue;
151  }
152 
153  // Cycle through cells
154  $tableCells = [];
155  for ($col = 1; $col <= $colCount; $col++) {
156  $columnConfig = $rowConfig['columns.'][$col . '.'] ?? null;
157  if (!$columnConfig) {
158  // Skip empty columns
159  continue;
160  }
161 
162  // Set table cell attributes
163  $tableCellAttributes = [
164  'class' => 'col-nowrap col-min',
165  ];
166  if (isset($columnConfig['colspan'])) {
167  $tableCellAttributes['colspan'] = $columnConfig['colspan'];
168  }
169  if (isset($columnConfig['rowspan'])) {
170  $tableCellAttributes['rowspan'] = $columnConfig['rowspan'];
171  }
172 
173  $columnKey = null;
174  $columnTitle = '';
175  $isRestricted = false;
176  $isUnassigned = true;
177  if (isset($columnConfig['colPos'])) {
178  // If colPos is defined, initialize column information (e.g. title and restricted state)
179  $columnKey = (int)$columnConfig['colPos'];
180  foreach ($tcaColumnsConfiguration as $tcaColumnConfiguration) {
181  if ($tcaColumnConfiguration['colPos'] === $columnKey) {
182  $columnTitle = '<strong>' . htmlspecialchars($lang->sL($tcaColumnConfiguration['title'])) . '</strong>';
183  $isRestricted = $tcaColumnConfiguration['isRestricted'];
184  $isUnassigned = false;
185  }
186  }
187  }
188 
189  // Generate the cell content, based on the columns' state (e.g. restricted or unassigned)
190  $cellContent = '';
191  if ($isRestricted) {
192  if ($hideRestrictedColumns) {
193  // Hide in case this column is not accessible and hideRestrictedColumns is set
194  $tableCellAttributes['class'] = 'hidden';
195  } else {
196  $cellContent = '
197  <p>
198  ' . $columnTitle . ' <em>(' . htmlspecialchars($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:noAccess')) . ')</em>
199  </p>';
200  $tableCellAttributes['class'] .= ' bg-danger bg-opacity-25';
201  }
202  } elseif ($isUnassigned) {
203  if ($hideRestrictedColumns) {
204  // Hide in case this column is not assigned and hideRestrictedColumns is set
205  $tableCellAttributes['class'] = 'hidden';
206  } else {
207  $cellContent = '
208  <em>
209  ' . htmlspecialchars($lang->sL($columnConfig['name']) ?: '') . '
210  ' . ' (' . htmlspecialchars($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:notAssigned')) . ')' . '
211  </em>';
212  $tableCellAttributes['class'] .= ' bg-warning bg-opacity-25';
213  }
214  } else {
215  // If not restricted and not unassigned, wrap column title and render list (if available)
216  $cellContent = '<p>' . $columnTitle . '</p>';
217  if (!empty($lines[$columnKey])) {
218  $cellContent .= '
219  <ul class="list-unstyled m-0">
220  ' . implode(LF, array_map(static fn(string $line): string => '<li>' . $line . '</li>', $lines[$columnKey])) . '
221  </ul>';
222  }
223  }
224 
225  // Add the table cell
226  $tableCells[] = '<td ' . GeneralUtility::implodeAttributes($tableCellAttributes) . '>' . $cellContent . '</td>';
227  }
228 
229  // Add the table row
230  $tableRows[] = '<tr>' . implode(LF, $tableCells) . '</tr>';
231  }
232 
233  // Create the table content
234  $tableContent = '<tbody>' . implode(LF, $tableRows) . '</tbody>';
235  } else {
236  // Build position map based on TCA colPos configuration
237  $tableCells = [];
238  foreach ($tcaColumnsConfiguration as $tcaColumnConfiguration) {
239  if ($hideRestrictedColumns && $tcaColumnConfiguration['isRestricted']) {
240  // Skip in case this column is not accessible and restricted columns should be hidden
241  continue;
242  }
243 
244  // Generate the cell content, based on the columns' state (e.g. restricted or unassigned)
245  $tableCellClasses = 'col-nowrap col-min';
246  $columnTitle = '<strong>' . htmlspecialchars($tcaColumnConfiguration['title']) . '</strong>';
247  if ($tcaColumnConfiguration['isRestricted']) {
248  // If this colPos is restricted, add an information to the column title and color the cell
249  $tableCellClasses .= ' bg-danger bg-opacity-25';
250  $cellContent = '
251  <p>
252  ' . $columnTitle . ' <em>(' . htmlspecialchars($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:noAccess')) . ')</em>
253  </p>';
254  } else {
255  // If not restricted, wrap column title and render list (if available)
256  $cellContent = '<p>' . $columnTitle . '</p>';
257  if (!empty($lines[$tcaColumnConfiguration['colPos']])) {
258  $cellContent .= '
259  <ul class="list-unstyled">
260  ' . implode(LF, array_map(static fn(string $line): string => '<li>' . $line . '</li>', $lines[$tcaColumnConfiguration['colPos']])) . '
261  </ul>';
262  }
263  }
264 
265  // Add the table cell
266  $tableCells[] = '<td class="' . $tableCellClasses . '">' . $cellContent . '</td>';
267  }
268 
269  // Create the table content
270  $tableContent = '<tbody><tr>' . implode(LF, $tableCells) . '</tr></tbody>';
271  }
272 
273  // Return the record map (table)
274  return '
275  <div class="table-fit">
276  <table class="table table-bordered table-vertical-top">
277  ' . $tableContent . '
278  </table>
279  </div>';
280  }
281 
286  protected function ‪getColumnsConfiguration(int $pageId): array
287  {
288  $backendLayout = $this->backendLayoutView->getBackendLayoutForPage($pageId);
289  if (!$backendLayout) {
290  return [];
291  }
292 
293  $items = [];
294  // Prepare the columns configuration (using named keys, etc.)
295  foreach ($backendLayout->getUsedColumns() as $colPos => $label) {
296  $items[] = [
297  'title' => $label,
298  'colPos' => (int)$colPos,
299  'isRestricted' => false,
300  ];
301  }
302 
303  $sharedColPosList = trim(BackendUtility::getPagesTSconfig($pageId)['mod.']['SHARED.']['colPos_list'] ?? '');
304  if ($sharedColPosList !== '') {
305  $activeColPosArray = array_unique(‪GeneralUtility::intExplode(',', $sharedColPosList));
306  if (!empty($items) && !empty($activeColPosArray)) {
307  foreach ($items as &$item) {
308  if (!in_array((int)$item['colPos'], $activeColPosArray, true)) {
309  $item['isRestricted'] = true;
310  }
311  }
312  unset($item);
313  }
314  }
315 
316  return $items;
317  }
318 
320  {
321  return ‪$GLOBALS['BE_USER'];
322  }
323 
325  {
326  return ‪$GLOBALS['LANG'];
327  }
328 }
‪TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction
Definition: HiddenRestriction.php:27
‪TYPO3\CMS\Backend\Tree\View\AbstractContentPagePositionMap\getRecordHeader
‪string getRecordHeader(array $row)
‪TYPO3\CMS\Backend\Tree\View\AbstractContentPagePositionMap\getColumnsConfiguration
‪getColumnsConfiguration(int $pageId)
Definition: AbstractContentPagePositionMap.php:286
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:52
‪TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction
Definition: EndTimeRestriction.php:27
‪TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction
Definition: StartTimeRestriction.php:27
‪TYPO3\CMS\Backend\Tree\View\AbstractContentPagePositionMap\insertPositionIcon
‪string insertPositionIcon(?array $row, int $colPos, int $pid)
‪TYPO3\CMS\Backend\Tree\View\AbstractContentPagePositionMap\$backendLayoutView
‪BackendLayoutView $backendLayoutView
Definition: AbstractContentPagePositionMap.php:42
‪TYPO3\CMS\Backend\Tree\View\AbstractContentPagePositionMap\getLanguageService
‪getLanguageService()
Definition: AbstractContentPagePositionMap.php:324
‪TYPO3\CMS\Backend\Tree\View\AbstractContentPagePositionMap\__construct
‪__construct(BackendLayoutView $backendLayoutView)
Definition: AbstractContentPagePositionMap.php:44
‪TYPO3\CMS\Backend\Tree\View\AbstractContentPagePositionMap\printContentElementColumns
‪string printContentElementColumns(int $pid)
Definition: AbstractContentPagePositionMap.php:74
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Tree\View
Definition: AbstractContentPagePositionMap.php:18
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪TYPO3\CMS\Backend\Tree\View\AbstractContentPagePositionMap
Definition: AbstractContentPagePositionMap.php:36
‪TYPO3\CMS\Backend\View\BackendLayoutView
Definition: BackendLayoutView.php:37
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Backend\Tree\View\AbstractContentPagePositionMap\printRecordMap
‪string printRecordMap(array $lines, array $tcaColumnsConfiguration, int $pid)
Definition: AbstractContentPagePositionMap.php:133
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Backend\Tree\View\AbstractContentPagePositionMap\getBackendUser
‪getBackendUser()
Definition: AbstractContentPagePositionMap.php:319
‪TYPO3\CMS\Backend\Tree\View\AbstractContentPagePositionMap\$cur_sys_language
‪int $cur_sys_language
Definition: AbstractContentPagePositionMap.php:40
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static list< int > intExplode(string $delimiter, string $string, bool $removeEmptyValues=false)
Definition: GeneralUtility.php:756
‪TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction
Definition: WorkspaceRestriction.php:39