‪TYPO3CMS  10.4
GridDataService.php
Go to the documentation of this file.
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 
17 
18 use Psr\EventDispatcher\EventDispatcherInterface;
19 use Psr\Log\LoggerAwareInterface;
20 use Psr\Log\LoggerAwareTrait;
37 
41 class ‪GridDataService implements LoggerAwareInterface
42 {
43  use LoggerAwareTrait;
44 
48  const ‪SIGNAL_GenerateDataArray_BeforeCaching = 'generateDataArray.beforeCaching';
52  const ‪SIGNAL_GenerateDataArray_PostProcesss = 'generateDataArray.postProcess';
56  const ‪SIGNAL_GetDataArray_PostProcesss = 'getDataArray.postProcess';
60  const ‪SIGNAL_SortDataArray_PostProcesss = 'sortDataArray.postProcess';
61 
62  const ‪GridColumn_Collection = 'Workspaces_Collection';
63  const ‪GridColumn_CollectionLevel = 'Workspaces_CollectionLevel';
64  const ‪GridColumn_CollectionParent = 'Workspaces_CollectionParent';
65  const ‪GridColumn_CollectionCurrent = 'Workspaces_CollectionCurrent';
66  const ‪GridColumn_CollectionChildren = 'Workspaces_CollectionChildren';
67 
73  protected ‪$currentWorkspace;
74 
80  protected ‪$dataArray = [];
81 
87  protected ‪$sort = '';
88 
94  protected ‪$sortDir = '';
95 
99  protected ‪$workspacesCache;
100 
105 
109  protected ‪$eventDispatcher;
110 
111  public function ‪__construct(EventDispatcherInterface ‪$eventDispatcher)
112  {
113  $this->eventDispatcher = ‪$eventDispatcher;
114  }
115 
125  public function ‪generateGridListFromVersions($versions, $parameter, ‪$currentWorkspace)
126  {
127  // Read the given parameters from grid. If the parameter is not set use default values.
128  $filterTxt = $parameter->filterTxt ?? '';
129  $start = isset($parameter->start) ? (int)$parameter->start : 0;
130  $limit = isset($parameter->limit) ? (int)$parameter->limit : 30;
131  $this->sort = $parameter->sort ?? 't3ver_oid';
132  $this->sortDir = $parameter->dir ?? 'ASC';
133  ‪if (is_int(‪$currentWorkspace)) {
134  $this->currentWorkspace = ‪$currentWorkspace;
135  } else {
136  throw new \InvalidArgumentException('No such workspace defined', 1476048304);
137  }
138  $this->‪generateDataArray($versions, $filterTxt);
139  return [
140  // Only count parent records for pagination
141  'total' => count(array_filter($this->dataArray, static function ($element) {
142  return (int)($element[self::GridColumn_CollectionLevel] ?? 0) === 0;
143  })),
144  'data' => $this->‪getDataArray($start, $limit)
145  ];
146  }
147 
154  protected function ‪generateDataArray(array $versions, $filterTxt)
155  {
156  $backendUser = $this->‪getBackendUser();
157  $workspaceAccess = $backendUser->checkWorkspace($backendUser->workspace);
158  $swapStage = $workspaceAccess['publish_access'] & 1 ? ‪StagesService::STAGE_PUBLISH_ID : 0;
159  $swapAccess = $backendUser->workspacePublishAccess($backendUser->workspace) && $backendUser->workspaceSwapAccess();
161  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
162  // check for dataArray in cache
163  if ($this->‪getDataArrayFromCache($versions, $filterTxt) === false) {
164  $stagesObj = GeneralUtility::makeInstance(StagesService::class);
165  $defaultGridColumns = [
166  self::GridColumn_Collection => 0,
167  self::GridColumn_CollectionLevel => 0,
168  self::GridColumn_CollectionParent => '',
169  self::GridColumn_CollectionCurrent => '',
170  self::GridColumn_CollectionChildren => 0,
171  ];
172  foreach ($versions as $table => $records) {
173  $table = (string)$table;
174  $hiddenField = $this->‪getTcaEnableColumnsFieldName($table, 'disabled');
175  $isRecordTypeAllowedToModify = $backendUser->check('tables_modify', $table);
176 
177  foreach ($records as $record) {
178  $origRecord = (array)‪BackendUtility::getRecord($table, $record['t3ver_oid']);
179  $versionRecord = (array)‪BackendUtility::getRecord($table, $record['uid']);
180  $combinedRecord = ‪CombinedRecord::createFromArrays($table, $origRecord, $versionRecord);
181  $hasDiff = $this->‪versionIsModified($combinedRecord);
182  $this->‪getIntegrityService()->‪checkElement($combinedRecord);
183 
184  if ($hiddenField !== null) {
185  $recordState = $this->‪workspaceState($versionRecord['t3ver_state'], $origRecord[$hiddenField], $versionRecord[$hiddenField], $hasDiff);
186  } else {
187  $recordState = $this->‪workspaceState($versionRecord['t3ver_state'], $hasDiff);
188  }
189 
190  $isDeletedPage = $table === 'pages' && $recordState === 'deleted';
191  $pageId = $table === 'pages' ? $record['uid'] : $record['pid'];
192  $viewUrl = GeneralUtility::makeInstance(PreviewUriBuilder::class)->buildUriForElement($table, $record['uid'], $origRecord, $versionRecord);
193  $workspaceRecordLabel = ‪BackendUtility::getRecordTitle($table, $versionRecord);
194  $liveRecordLabel = ‪BackendUtility::getRecordTitle($table, $origRecord);
195  [$pathWorkspaceCropped, $pathWorkspace] = ‪BackendUtility::getRecordPath((int)$record['wspid'], '', 15, 1000);
196  $versionArray = [];
197  $versionArray['table'] = $table;
198  $versionArray['id'] = $table . ':' . $record['uid'];
199  $versionArray['uid'] = $record['uid'];
200  $versionArray = array_merge($versionArray, $defaultGridColumns);
201  $versionArray['label_Workspace'] = htmlspecialchars($workspaceRecordLabel);
202  $versionArray['label_Workspace_crop'] = htmlspecialchars(GeneralUtility::fixed_lgd_cs($workspaceRecordLabel, $backendUser->uc['titleLen']));
203  $versionArray['label_Live'] = htmlspecialchars($liveRecordLabel);
204  $versionArray['label_Live_crop'] = htmlspecialchars(GeneralUtility::fixed_lgd_cs($liveRecordLabel, $backendUser->uc['titleLen']));
205  $versionArray['label_Stage'] = htmlspecialchars($stagesObj->getStageTitle($versionRecord['t3ver_stage']));
206  $tempStage = $stagesObj->getNextStage($versionRecord['t3ver_stage']);
207  $versionArray['label_nextStage'] = htmlspecialchars($stagesObj->getStageTitle($tempStage['uid']));
208  $versionArray['value_nextStage'] = (int)$tempStage['uid'];
209  $tempStage = $stagesObj->getPrevStage($versionRecord['t3ver_stage']);
210  $versionArray['label_prevStage'] = htmlspecialchars($stagesObj->getStageTitle($tempStage['uid']));
211  $versionArray['value_prevStage'] = (int)$tempStage['uid'];
212  $versionArray['path_Live'] = htmlspecialchars(‪BackendUtility::getRecordPath($record['livepid'], '', 999));
213  $versionArray['path_Workspace'] = htmlspecialchars($pathWorkspace);
214  $versionArray['path_Workspace_crop'] = htmlspecialchars($pathWorkspaceCropped);
215  $versionArray['workspace_Title'] = htmlspecialchars(‪WorkspaceService::getWorkspaceTitle($versionRecord['t3ver_wsid']));
216  $versionArray['workspace_Tstamp'] = $versionRecord['tstamp'];
217  $versionArray['workspace_Formated_Tstamp'] = ‪BackendUtility::datetime($versionRecord['tstamp']);
218  $versionArray['t3ver_wsid'] = $versionRecord['t3ver_wsid'];
219  $versionArray['t3ver_oid'] = $record['t3ver_oid'];
220  $versionArray['livepid'] = $record['livepid'];
221  $versionArray['stage'] = $versionRecord['t3ver_stage'];
222  $versionArray['icon_Live'] = $iconFactory->getIconForRecord($table, $origRecord, ‪Icon::SIZE_SMALL)->render();
223  $versionArray['icon_Workspace'] = $iconFactory->getIconForRecord($table, $versionRecord, ‪Icon::SIZE_SMALL)->render();
224  $languageValue = $this->‪getLanguageValue($table, $versionRecord);
225  $versionArray['languageValue'] = $languageValue;
226  $versionArray['language'] = [
227  'icon' => $iconFactory->getIcon($this->‪getSystemLanguageValue($languageValue, $pageId, 'flagIcon'), ‪Icon::SIZE_SMALL)->render()
228  ];
229  $versionArray['allowedAction_nextStage'] = $isRecordTypeAllowedToModify && $stagesObj->isNextStageAllowedForUser($versionRecord['t3ver_stage']);
230  $versionArray['allowedAction_prevStage'] = $isRecordTypeAllowedToModify && $stagesObj->isPrevStageAllowedForUser($versionRecord['t3ver_stage']);
231  if ($swapAccess && $swapStage != 0 && $versionRecord['t3ver_stage'] == $swapStage) {
232  $versionArray['allowedAction_swap'] = $isRecordTypeAllowedToModify && $stagesObj->isNextStageAllowedForUser($swapStage);
233  } elseif ($swapAccess && $swapStage == 0) {
234  $versionArray['allowedAction_swap'] = $isRecordTypeAllowedToModify;
235  } else {
236  $versionArray['allowedAction_swap'] = false;
237  }
238  $versionArray['allowedAction_delete'] = $isRecordTypeAllowedToModify;
239  // preview and editing of a deleted page won't work ;)
240  $versionArray['allowedAction_view'] = !$isDeletedPage && $viewUrl;
241  $versionArray['allowedAction_edit'] = $isRecordTypeAllowedToModify && !$isDeletedPage;
242  $versionArray['allowedAction_editVersionedPage'] = $isRecordTypeAllowedToModify && !$isDeletedPage;
243  $versionArray['state_Workspace'] = $recordState;
244  $versionArray['hasChanges'] = ($recordState === 'unchanged') ? false: true;
245  // Allows to be overridden by PSR-14 event to dynamically modify the expand / collapse state
246  $versionArray['expanded'] = false;
247 
248  $versionArray = array_merge(
249  $versionArray,
250  $this->‪getAdditionalColumnService()->getData($combinedRecord)
251  );
252 
253  if ($filterTxt == '' || $this->‪isFilterTextInVisibleColumns($filterTxt, $versionArray)) {
254  $versionIdentifier = $versionArray['id'];
255  $this->dataArray[$versionIdentifier] = $versionArray;
256  }
257  }
258  }
259 
260  // Trigger a PSR-14 event
261  $event = new ‪AfterCompiledCacheableDataForWorkspaceEvent($this, $this->dataArray, $versions);
262  $this->eventDispatcher->dispatch($event);
263  $this->dataArray = $event->getData();
264  $versions = $event->getVersions();
265  // Enrich elements after everything has been processed:
266  foreach ($this->dataArray as &$element) {
267  $identifier = $element['table'] . ':' . $element['t3ver_oid'];
268  $element['integrity'] = [
269  'status' => $this->‪getIntegrityService()->‪getStatusRepresentation($identifier),
270  'messages' => htmlspecialchars((string)$this->‪getIntegrityService()->getIssueMessages($identifier, true))
271  ];
272  }
273  $this->‪setDataArrayIntoCache($versions, $filterTxt);
274  }
275 
276  // Trigger a PSR-14 event
277  $event = new ‪AfterDataGeneratedForWorkspaceEvent($this, $this->dataArray, $versions);
278  $this->eventDispatcher->dispatch($event);
279  $this->dataArray = $event->getData();
280  $this->‪sortDataArray();
282  }
283 
284  protected function ‪versionIsModified(‪CombinedRecord $combinedRecord): bool
285  {
286  $remoteServer = GeneralUtility::makeInstance(RemoteServer::class);
287 
288  $params = new \StdClass();
289  $params->stage = $combinedRecord->‪getVersionRecord()->‪getRow()['t3ver_stage'];
290  $params->t3ver_oid = $combinedRecord->‪getLiveRecord()->‪getUid();
291  $params->table = $combinedRecord->‪getLiveRecord()->‪getTable();
292  $params->uid = $combinedRecord->‪getVersionRecord()->‪getUid();
293 
294  $result = $remoteServer->getRowDetails($params);
295  return !empty($result['data'][0]['diff']);
296  }
297 
302  protected function ‪resolveDataArrayDependencies()
303  {
304  $collectionService = $this->‪getDependencyCollectionService();
305  $dependencyResolver = $collectionService->getDependencyResolver();
306 
307  foreach ($this->dataArray as $dataElement) {
308  $dependencyResolver->addElement($dataElement['table'], $dataElement['uid']);
309  }
310 
311  $this->dataArray = $collectionService->process($this->dataArray);
312  }
313 
321  protected function ‪getDataArray($start, $limit)
322  {
323  $dataArrayCount = count($this->dataArray);
324  $start = $this->‪calculateStartWithCollections($start);
325  $end = ($start + $limit < $dataArrayCount ? $start + $limit : $dataArrayCount);
326 
327  // Ensure that there are numerical indexes
328  $this->dataArray = array_values($this->dataArray);
329  // Fill the data array part
330  $dataArrayPart = $this->‪fillDataArrayPart($start, $end);
331 
332  // Trigger a PSR-14 event
333  $event = new GetVersionedDataEvent($this, $this->dataArray, $start, $limit, $dataArrayPart);
334  $this->eventDispatcher->dispatch($event);
335  $this->dataArray = $event->getData();
336  return $event->getDataArrayPart();
337  }
338 
342  protected function ‪initializeWorkspacesCachingFramework()
343  {
344  $this->workspacesCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('workspaces_cache');
345  }
346 
353  protected function ‪setDataArrayIntoCache(array $versions, $filterTxt)
354  {
355  $hash = $this->‪calculateHash($versions, $filterTxt);
356  $this->workspacesCache->set(
357  $hash,
358  $this->dataArray,
359  [
360  (string)$this->currentWorkspace,
361  'user_' . $this->‪getBackendUser()->user['uid']
362  ]
363  );
364  }
365 
373  protected function ‪getDataArrayFromCache(array $versions, $filterTxt)
374  {
375  $cacheEntry = false;
376  $hash = $this->‪calculateHash($versions, $filterTxt);
377  $content = $this->workspacesCache->get($hash);
378  if ($content !== false) {
379  $this->dataArray = $content;
380  $cacheEntry = true;
381  }
382  return $cacheEntry;
383  }
384 
392  protected function ‪calculateHash(array $versions, $filterTxt)
393  {
394  $backendUser = $this->‪getBackendUser();
395  $hashArray = [
396  $backendUser->workspace,
397  $backendUser->user['uid'],
398  $versions,
399  $filterTxt,
403  ];
404  $hash = md5(serialize($hashArray));
405  return $hash;
406  }
407 
412  protected function ‪sortDataArray()
413  {
414  if (is_array($this->dataArray)) {
415  switch ($this->sort) {
416  case 'uid':
417  case 'change':
418  case 'workspace_Tstamp':
419  case 't3ver_oid':
420  case 'liveid':
421  case 'livepid':
422  case 'languageValue':
423  uasort($this->dataArray, [$this, 'intSort']);
424  break;
425  case 'label_Workspace':
426  case 'label_Live':
427  case 'label_Stage':
428  case 'workspace_Title':
429  case 'path_Live':
430  // case 'path_Workspace': This is the first sorting attribute
431  uasort($this->dataArray, [$this, 'stringSort']);
432  break;
433  default:
434  // Do nothing
435  }
436  } else {
437  $this->logger->critical('Try to sort "' . $this->sort . '" in "\\TYPO3\\CMS\\Workspaces\\Service\\GridDataService::sortDataArray" but $this->dataArray is empty! This might be the bug #26422 which could not be reproduced yet.');
438  }
439  // Trigger an event for extensibility
440  $event = new SortVersionedDataEvent($this, $this->dataArray, $this->sort, $this->sortDir);
441  $this->eventDispatcher->dispatch($event);
442  $this->dataArray = $event->getData();
443  $this->sort = $event->getSortColumn();
444  $this->sortDir = $event->getSortDirection();
445  }
446 
454  protected function ‪intSort(array $a, array $b)
455  {
456  if (!$this->‪isSortable($a, $b)) {
457  return 0;
458  }
459  // First sort by using the page-path in current workspace
460  $path_cmp = strcasecmp($a['path_Workspace'], $b['path_Workspace']);
461  if ($path_cmp < 0) {
462  return $path_cmp;
463  }
464  if ($path_cmp == 0) {
465  if ($a[$this->sort] == $b[$this->sort]) {
466  return 0;
467  }
468  if ($this->sortDir === 'ASC') {
469  return $a[‪$this->sort] < $b[‪$this->sort] ? -1 : 1;
470  }
471  if ($this->sortDir === 'DESC') {
472  return $a[‪$this->sort] > $b[‪$this->sort] ? -1 : 1;
473  }
474  } elseif ($path_cmp > 0) {
475  return $path_cmp;
476  }
477  return 0;
478  }
479 
487  protected function ‪stringSort($a, $b)
488  {
489  if (!$this->‪isSortable($a, $b)) {
490  return 0;
491  }
492  $path_cmp = strcasecmp($a['path_Workspace'], $b['path_Workspace']);
493  if ($path_cmp < 0) {
494  return $path_cmp;
495  }
496  if ($path_cmp == 0) {
497  if ($a[$this->sort] == $b[$this->sort]) {
498  return 0;
499  }
500  if ($this->sortDir === 'ASC') {
501  return strcasecmp($a[$this->sort], $b[$this->sort]);
502  }
503  if ($this->sortDir === 'DESC') {
504  return strcasecmp($a[$this->sort], $b[$this->sort]) * -1;
505  }
506  } elseif ($path_cmp > 0) {
507  return $path_cmp;
508  }
509  return 0;
510  }
511 
521  protected function ‪isSortable(array $a, array $b)
522  {
523  return
526  ;
527  }
528 
537  protected function ‪isFilterTextInVisibleColumns($filterText, array $versionArray)
538  {
539  $backendUser = $this->‪getBackendUser();
540  if (is_array($backendUser->uc['moduleData']['Workspaces'][$backendUser->workspace]['columns'])) {
541  $visibleColumns = $backendUser->uc['moduleData']['Workspaces'][$backendUser->workspace]['columns'];
542  } else {
543  $visibleColumns = [
544  'workspace_Formated_Tstamp' => ['hidden' => 0],
545  'change' => ['hidden' => 0],
546  'path_Workspace' => ['hidden' => 0],
547  'path_Live' => ['hidden' => 0],
548  'label_Live' => ['hidden' => 0],
549  'label_Stage' => ['hidden' => 0],
550  'label_Workspace' => ['hidden' => 0],
551  ];
552  }
553  foreach ($visibleColumns as $column => $value) {
554  if (isset($value['hidden']) && isset($column) && isset($versionArray[$column])) {
555  if ($value['hidden'] == 0) {
556  switch ($column) {
557  case 'workspace_Tstamp':
558  if (stripos($versionArray['workspace_Formated_Tstamp'], $filterText) !== false) {
559  return true;
560  }
561  break;
562  case 'change':
563  if (stripos((string)$versionArray[$column], str_replace('%', '', $filterText)) !== false) {
564  return true;
565  }
566  break;
567  default:
568  if (stripos((string)$versionArray[$column], $filterText) !== false) {
569  return true;
570  }
571  }
572  }
573  }
574  }
575  return false;
576  }
577 
588  protected function ‪workspaceState($stateId, $hiddenOnline = false, $hiddenOffline = false, $hasDiff = true)
589  {
590  $hiddenState = null;
591  if ($hiddenOnline == 0 && $hiddenOffline == 1) {
592  $hiddenState = 'hidden';
593  } elseif ($hiddenOnline == 1 && $hiddenOffline == 0) {
594  $hiddenState = 'unhidden';
595  }
596  switch ($stateId) {
598  $state = 'new';
599  break;
601  $state = 'deleted';
602  break;
604  $state = 'moved';
605  break;
606  default:
607  if (!$hasDiff) {
608  $state = 'unchanged';
609  } else {
610  $state = ($hiddenState ?: 'modified');
611  }
612  }
613 
614  return $state;
615  }
616 
624  protected function ‪getTcaEnableColumnsFieldName($table, $type)
625  {
626  $fieldName = null;
627 
628  if (!empty(‪$GLOBALS['TCA'][$table]['ctrl']['enablecolumns'][$type])) {
629  $fieldName = ‪$GLOBALS['TCA'][$table]['ctrl']['enablecolumns'][$type];
630  }
631 
632  return $fieldName;
633  }
634 
643  protected function ‪getLanguageValue($table, array $record)
644  {
645  $languageValue = 0;
647  $languageField = ‪$GLOBALS['TCA'][$table]['ctrl']['languageField'];
648  if (!empty($record[$languageField])) {
649  $languageValue = $record[$languageField];
650  }
651  }
652  return $languageValue;
653  }
654 
664  protected function ‪getSystemLanguageValue($id, $pageId, $key)
665  {
666  $value = null;
667  $systemLanguages = $this->‪getSystemLanguages((int)$pageId);
668  if (!empty($systemLanguages[$id][$key])) {
669  $value = $systemLanguages[$id][$key];
670  }
671  return $value;
672  }
673 
680  protected function ‪calculateStartWithCollections(int $start): int
681  {
682  // The recordsCount is the real record items count, while the
683  // parentRecordsCount only takes the parent records into account
684  $recordsCount = $parentRecordsCount = 0;
685  while ($parentRecordsCount < $start) {
686  // As soon as no more item exists in the dataArray, the loop needs to end
687  // prematurely to prevent invalid items which would may led to some unexpected
688  // behaviour. Note: This usually should never happen since these records must
689  // exists => As they were responsible for increasing the start value. However to
690  // prevent errors in case multiple different users manipulate the records count
691  // somehow simultaneously, we apply this check to be save.
692  if (!isset($this->dataArray[$recordsCount])) {
693  break;
694  }
695  // Loop over the dataArray until we found enough parent records
696  $item = $this->dataArray[$recordsCount];
697  if (($item[self::GridColumn_CollectionLevel] ?? 0) === 0) {
698  // In case the current parent record is the last one ($start is reached),
699  // ensure its collection children are counted as well.
700  if (($parentRecordsCount + 1) === $start && (int)($item[self::GridColumn_Collection] ?? 0) !== 0) {
701  // By not providing the third parameter, we only count the collection children recursively
702  $this->‪addCollectionChildrenRecursive($item, $recordsCount);
703  }
704  // Only increase the parent records count in case $item is a parent record
705  $parentRecordsCount++;
706  }
707  // Always increase the record items count
708  $recordsCount++;
709  }
710 
711  return $recordsCount;
712  }
713 
723  private function ‪fillDataArrayPart(int $start, int $end): array
724  {
725  // Initialize empty data array part
726  $dataArrayPart = [];
727  // The recordsCount is the real record items count, while the
728  // parentRecordsCount only takes the parent records into account.
729  $itemsCount = $parentRecordsCount = $start;
730  while ($parentRecordsCount < $end) {
731  // As soon as no more item exists in the dataArray, the loop needs to end
732  // prematurely to prevent invalid items which would trigger JavaScript errors.
733  if (!isset($this->dataArray[$itemsCount])) {
734  break;
735  }
736  // Loop over the dataArray until we found enough parent records
737  $item = $this->dataArray[$itemsCount];
738  // Add the item to the $dataArrayPart
739  $dataArrayPart[] = $item;
740  if (($item[self::GridColumn_CollectionLevel] ?? 0) === 0) {
741  // In case the current parent record is the last one ($end is reached),
742  // ensure its collection children are added as well.
743  if (($parentRecordsCount + 1) === $end && (int)($item[self::GridColumn_Collection] ?? 0) !== 0) {
744  // Add collection children recursively
745  $this->‪addCollectionChildrenRecursive($item, $itemsCount, $dataArrayPart);
746  }
747  // Only increase the parent records count in case $item is a parent record
748  $parentRecordsCount++;
749  }
750  // Always increase the record items count
751  $itemsCount++;
752  }
753  return $dataArrayPart;
754  }
755 
763  protected function ‪addCollectionChildrenRecursive(array $item, int &$recordsCount, array &$dataArrayPart = []): void
764  {
765  $collectionParent = (string)$item[self::GridColumn_CollectionCurrent];
766  foreach ($this->dataArray as $element) {
767  if ((string)($element[‪self::GridColumn_CollectionParent] ?? '') === $collectionParent) {
768  // Increase the "real" record items count
769  $recordsCount++;
770  // Fetch the children from the dataArray using the current record items
771  // count. This is possible since the dataArray is already sorted.
772  $child = $this->dataArray[$recordsCount];
773  // In case $dataArrayPart is not given, just count the item
774  if ($dataArrayPart !== []) {
775  // Add the children
776  $dataArrayPart[] = $child;
777  }
778  // In case the $child is also a collection, add it's children as well (recursively)
779  if ((int)($child[‪self::GridColumn_Collection] ?? 0) !== 0) {
780  $this->‪addCollectionChildrenRecursive($child, $recordsCount, $dataArrayPart);
781  }
782  }
783  }
784  }
785 
791  public function ‪getSystemLanguages(?int $pageId)
792  {
793  return GeneralUtility::makeInstance(TranslationConfigurationProvider::class)->getSystemLanguages((int)$pageId);
794  }
795 
801  protected function ‪getIntegrityService()
802  {
803  if (!isset($this->integrityService)) {
804  $this->integrityService = GeneralUtility::makeInstance(IntegrityService::class);
805  }
807  }
808 
812  protected function ‪getDependencyCollectionService()
813  {
814  return GeneralUtility::makeInstance(CollectionService::class);
815  }
816 
820  protected function ‪getAdditionalColumnService()
821  {
822  return GeneralUtility::makeInstance(AdditionalColumnService::class);
823  }
824 
828  protected function ‪getBackendUser()
829  {
830  return ‪$GLOBALS['BE_USER'];
831  }
832 }
‪TYPO3\CMS\Core\Imaging\Icon\SIZE_SMALL
‪const SIZE_SMALL
Definition: Icon.php:30
‪TYPO3\CMS\Workspaces\Service\GridDataService\sortDataArray
‪sortDataArray()
Definition: GridDataService.php:405
‪TYPO3\CMS\Workspaces\Service\IntegrityService\checkElement
‪checkElement(CombinedRecord $element)
Definition: IntegrityService.php:105
‪TYPO3\CMS\Workspaces\Service\GridDataService\$currentWorkspace
‪int $currentWorkspace
Definition: GridDataService.php:72
‪TYPO3\CMS\Workspaces\Domain\Model\CombinedRecord
Definition: CombinedRecord.php:24
‪TYPO3\CMS\Workspaces\Event\SortVersionedDataEvent
Definition: SortVersionedDataEvent.php:26
‪TYPO3\CMS\Workspaces\Service\GridDataService\workspaceState
‪string workspaceState($stateId, $hiddenOnline=false, $hiddenOffline=false, $hasDiff=true)
Definition: GridDataService.php:581
‪TYPO3\CMS\Workspaces\Service\GridDataService\$workspacesCache
‪TYPO3 CMS Core Cache Frontend FrontendInterface $workspacesCache
Definition: GridDataService.php:94
‪TYPO3\CMS\Backend\Utility\BackendUtility\datetime
‪static string datetime($value)
Definition: BackendUtility.php:989
‪TYPO3\CMS\Workspaces\Service
Definition: AdditionalColumnService.php:16
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:26
‪TYPO3\CMS\Workspaces\Event\AfterDataGeneratedForWorkspaceEvent
Definition: AfterDataGeneratedForWorkspaceEvent.php:26
‪TYPO3\CMS\Workspaces\Service\GridDataService\getDependencyCollectionService
‪Dependency CollectionService getDependencyCollectionService()
Definition: GridDataService.php:805
‪TYPO3\CMS\Workspaces\Domain\Model\DatabaseRecord\getTable
‪string getTable()
Definition: DatabaseRecord.php:81
‪TYPO3\CMS\Workspaces\Service\GridDataService\getSystemLanguageValue
‪string null getSystemLanguageValue($id, $pageId, $key)
Definition: GridDataService.php:657
‪TYPO3\CMS\Workspaces\Service\GridDataService\initializeWorkspacesCachingFramework
‪initializeWorkspacesCachingFramework()
Definition: GridDataService.php:335
‪TYPO3\CMS\Workspaces\Service\GridDataService\$sortDir
‪string $sortDir
Definition: GridDataService.php:90
‪if
‪if(PHP_SAPI !=='cli')
Definition: splitAcceptanceTests.php:33
‪TYPO3\CMS\Workspaces\Service\GridDataService\intSort
‪int intSort(array $a, array $b)
Definition: GridDataService.php:447
‪TYPO3\CMS\Workspaces\Service\GridDataService\calculateStartWithCollections
‪int calculateStartWithCollections(int $start)
Definition: GridDataService.php:673
‪TYPO3\CMS\Workspaces\Service\IntegrityService\getStatusRepresentation
‪string getStatusRepresentation($identifier=null)
Definition: IntegrityService.php:176
‪TYPO3\CMS\Workspaces\Service\GridDataService\getDataArrayFromCache
‪bool getDataArrayFromCache(array $versions, $filterTxt)
Definition: GridDataService.php:366
‪TYPO3\CMS\Workspaces\Service\GridDataService\generateDataArray
‪generateDataArray(array $versions, $filterTxt)
Definition: GridDataService.php:147
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:33
‪TYPO3\CMS\Workspaces\Service\GridDataService\stringSort
‪int stringSort($a, $b)
Definition: GridDataService.php:480
‪TYPO3\CMS\Core\Versioning\VersionState\DELETE_PLACEHOLDER
‪const DELETE_PLACEHOLDER
Definition: VersionState.php:55
‪TYPO3\CMS\Workspaces\Service\GridDataService\calculateHash
‪string calculateHash(array $versions, $filterTxt)
Definition: GridDataService.php:385
‪TYPO3\CMS\Workspaces\Service\GridDataService\isFilterTextInVisibleColumns
‪bool isFilterTextInVisibleColumns($filterText, array $versionArray)
Definition: GridDataService.php:530
‪TYPO3\CMS\Core\Versioning\VersionState\MOVE_POINTER
‪const MOVE_POINTER
Definition: VersionState.php:73
‪TYPO3\CMS\Workspaces\Service\AdditionalColumnService
Definition: AdditionalColumnService.php:27
‪TYPO3\CMS\Workspaces\Service\GridDataService\$sort
‪string $sort
Definition: GridDataService.php:84
‪TYPO3\CMS\Workspaces\Service\GridDataService\getAdditionalColumnService
‪AdditionalColumnService getAdditionalColumnService()
Definition: GridDataService.php:813
‪TYPO3\CMS\Workspaces\Service\StagesService\STAGE_PUBLISH_ID
‪const STAGE_PUBLISH_ID
Definition: StagesService.php:38
‪TYPO3\CMS\Workspaces\Service\GridDataService\__construct
‪__construct(EventDispatcherInterface $eventDispatcher)
Definition: GridDataService.php:104
‪TYPO3\CMS\Workspaces\Service\GridDataService\isSortable
‪bool isSortable(array $a, array $b)
Definition: GridDataService.php:514
‪TYPO3\CMS\Workspaces\Service\GridDataService\SIGNAL_GetDataArray_PostProcesss
‪const SIGNAL_GetDataArray_PostProcesss
Definition: GridDataService.php:56
‪TYPO3\CMS\Workspaces\Service\GridDataService\GridColumn_CollectionCurrent
‪const GridColumn_CollectionCurrent
Definition: GridDataService.php:65
‪TYPO3\CMS\Workspaces\Service\GridDataService\generateGridListFromVersions
‪array generateGridListFromVersions($versions, $parameter, $currentWorkspace)
Definition: GridDataService.php:118
‪TYPO3\CMS\Workspaces\Controller\Remote\RemoteServer
Definition: RemoteServer.php:48
‪TYPO3\CMS\Workspaces\Service\GridDataService\SIGNAL_GenerateDataArray_PostProcesss
‪const SIGNAL_GenerateDataArray_PostProcesss
Definition: GridDataService.php:52
‪TYPO3\CMS\Workspaces\Service\Dependency\CollectionService
Definition: CollectionService.php:32
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder
Definition: PreviewUriBuilder.php:43
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecordTitle
‪static string getRecordTitle($table, $row, $prep=false, $forceResult=true)
Definition: BackendUtility.php:1541
‪TYPO3\CMS\Workspaces\Service\IntegrityService
Definition: IntegrityService.php:27
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:35
‪TYPO3\CMS\Workspaces\Service\GridDataService\addCollectionChildrenRecursive
‪addCollectionChildrenRecursive(array $item, int &$recordsCount, array &$dataArrayPart=[])
Definition: GridDataService.php:756
‪TYPO3\CMS\Workspaces\Service\GridDataService\getSystemLanguages
‪array getSystemLanguages(?int $pageId)
Definition: GridDataService.php:784
‪TYPO3\CMS\Workspaces\Service\GridDataService\$eventDispatcher
‪EventDispatcherInterface $eventDispatcher
Definition: GridDataService.php:102
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Workspaces\Domain\Model\CombinedRecord\createFromArrays
‪static CombinedRecord createFromArrays($table, array $liveRow, array $versionRow)
Definition: CombinedRecord.php:60
‪TYPO3\CMS\Workspaces\Domain\Model\DatabaseRecord\getUid
‪int getUid()
Definition: DatabaseRecord.php:101
‪TYPO3\CMS\Workspaces\Service\GridDataService\getTcaEnableColumnsFieldName
‪string null getTcaEnableColumnsFieldName($table, $type)
Definition: GridDataService.php:617
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:75
‪TYPO3\CMS\Workspaces\Event\AfterCompiledCacheableDataForWorkspaceEvent
Definition: AfterCompiledCacheableDataForWorkspaceEvent.php:26
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecord
‪static array null getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
Definition: BackendUtility.php:95
‪TYPO3\CMS\Core\Versioning\VersionState
Definition: VersionState.php:24
‪TYPO3\CMS\Workspaces\Domain\Model\CombinedRecord\getLiveRecord
‪DatabaseRecord getLiveRecord()
Definition: CombinedRecord.php:106
‪TYPO3\CMS\Workspaces\Service\GridDataService\getLanguageValue
‪int getLanguageValue($table, array $record)
Definition: GridDataService.php:636
‪TYPO3\CMS\Workspaces\Service\GridDataService\GridColumn_CollectionLevel
‪const GridColumn_CollectionLevel
Definition: GridDataService.php:63
‪TYPO3\CMS\Core\Versioning\VersionState\NEW_PLACEHOLDER_VERSION
‪const NEW_PLACEHOLDER_VERSION
Definition: VersionState.php:33
‪TYPO3\CMS\Workspaces\Service\GridDataService\fillDataArrayPart
‪array fillDataArrayPart(int $start, int $end)
Definition: GridDataService.php:716
‪TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider
Definition: TranslationConfigurationProvider.php:35
‪TYPO3\CMS\Backend\Utility\BackendUtility\isTableLocalizable
‪static bool isTableLocalizable($table)
Definition: BackendUtility.php:578
‪TYPO3\CMS\Workspaces\Service\GridDataService\versionIsModified
‪versionIsModified(CombinedRecord $combinedRecord)
Definition: GridDataService.php:277
‪TYPO3\CMS\Workspaces\Service\GridDataService\getIntegrityService
‪IntegrityService getIntegrityService()
Definition: GridDataService.php:794
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Workspaces\Service\GridDataService\$dataArray
‪array $dataArray
Definition: GridDataService.php:78
‪TYPO3\CMS\Workspaces\Domain\Model\DatabaseRecord\getRow
‪array getRow()
Definition: DatabaseRecord.php:121
‪TYPO3\CMS\Workspaces\Service\GridDataService\getBackendUser
‪BackendUserAuthentication getBackendUser()
Definition: GridDataService.php:821
‪TYPO3\CMS\Workspaces\Service\GridDataService\GridColumn_Collection
‪const GridColumn_Collection
Definition: GridDataService.php:62
‪TYPO3\CMS\Workspaces\Service\GridDataService\GridColumn_CollectionParent
‪const GridColumn_CollectionParent
Definition: GridDataService.php:64
‪TYPO3\CMS\Workspaces\Service\GridDataService\GridColumn_CollectionChildren
‪const GridColumn_CollectionChildren
Definition: GridDataService.php:66
‪TYPO3\CMS\Workspaces\Service\GridDataService\getDataArray
‪array getDataArray($start, $limit)
Definition: GridDataService.php:314
‪TYPO3\CMS\Workspaces\Service\GridDataService\setDataArrayIntoCache
‪setDataArrayIntoCache(array $versions, $filterTxt)
Definition: GridDataService.php:346
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecordPath
‪static mixed getRecordPath($uid, $clause, $titleLimit, $fullTitleLimit=0)
Definition: BackendUtility.php:546
‪TYPO3\CMS\Workspaces\Domain\Model\CombinedRecord\getVersionRecord
‪DatabaseRecord getVersionRecord()
Definition: CombinedRecord.php:126
‪TYPO3\CMS\Workspaces\Event\GetVersionedDataEvent
Definition: GetVersionedDataEvent.php:28
‪TYPO3\CMS\Workspaces\Service\GridDataService\$integrityService
‪IntegrityService $integrityService
Definition: GridDataService.php:98
‪TYPO3\CMS\Workspaces\Service\GridDataService\SIGNAL_SortDataArray_PostProcesss
‪const SIGNAL_SortDataArray_PostProcesss
Definition: GridDataService.php:60
‪TYPO3\CMS\Workspaces\Service\GridDataService\SIGNAL_GenerateDataArray_BeforeCaching
‪const SIGNAL_GenerateDataArray_BeforeCaching
Definition: GridDataService.php:48
‪TYPO3\CMS\Workspaces\Service\GridDataService\resolveDataArrayDependencies
‪resolveDataArrayDependencies()
Definition: GridDataService.php:295
‪TYPO3\CMS\Workspaces\Service\WorkspaceService\getWorkspaceTitle
‪static string getWorkspaceTitle($wsId)
Definition: WorkspaceService.php:120
‪TYPO3\CMS\Workspaces\Service\GridDataService
Definition: GridDataService.php:42