4bf42e996075d8b339aff705a47013c443c36f7f
[Packages/TYPO3.CMS.git] / typo3 / sysext / workspaces / Classes / Service / GridDataService.php
1 <?php
2 namespace TYPO3\CMS\Workspaces\Service;
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
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19
20 /**
21 * Grid data service
22 *
23 * @author Workspaces Team (http://forge.typo3.org/projects/show/typo3v4-workspaces)
24 */
25 class GridDataService {
26
27 const SIGNAL_GenerateDataArray_BeforeCaching = 'generateDataArray.beforeCaching';
28 const SIGNAL_GenerateDataArray_PostProcesss = 'generateDataArray.postProcess';
29 const SIGNAL_GetDataArray_PostProcesss = 'getDataArray.postProcess';
30 const SIGNAL_SortDataArray_PostProcesss = 'sortDataArray.postProcess';
31
32 const GridColumn_Collection = 'Workspaces_Collection';
33 const GridColumn_CollectionLevel = 'Workspaces_CollectionLevel';
34 const GridColumn_CollectionParent = 'Workspaces_CollectionParent';
35 const GridColumn_CollectionCurrent = 'Workspaces_CollectionCurrent';
36 const GridColumn_CollectionChildren = 'Workspaces_CollectionChildren';
37
38 /**
39 * Id of the current active workspace.
40 *
41 * @var int
42 */
43 protected $currentWorkspace = NULL;
44
45 /**
46 * Version record information (filtered, sorted and limited)
47 *
48 * @var array
49 */
50 protected $dataArray = array();
51
52 /**
53 * Name of the field used for sorting.
54 *
55 * @var string
56 */
57 protected $sort = '';
58
59 /**
60 * Direction used for sorting (ASC, DESC).
61 *
62 * @var string
63 */
64 protected $sortDir = '';
65
66 /**
67 * @var \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
68 */
69 protected $workspacesCache = NULL;
70
71 /**
72 * @var array
73 */
74 protected $systemLanguages;
75
76 /**
77 * @var \TYPO3\CMS\Workspaces\Service\IntegrityService
78 */
79 protected $integrityService;
80
81 /**
82 * Generates grid list array from given versions.
83 *
84 * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid and t3ver_oid fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid
85 * @param object $parameter Parameters as submitted by JavaScript component
86 * @param int $currentWorkspace The current workspace
87 * @return array Version record information (filtered, sorted and limited)
88 * @throws \InvalidArgumentException
89 */
90 public function generateGridListFromVersions($versions, $parameter, $currentWorkspace) {
91 // Read the given parameters from grid. If the parameter is not set use default values.
92 $filterTxt = isset($parameter->filterTxt) ? $parameter->filterTxt : '';
93 $start = isset($parameter->start) ? (int)$parameter->start : 0;
94 $limit = isset($parameter->limit) ? (int)$parameter->limit : 30;
95 $this->sort = isset($parameter->sort) ? $parameter->sort : 't3ver_oid';
96 $this->sortDir = isset($parameter->dir) ? $parameter->dir : 'ASC';
97 if (is_int($currentWorkspace)) {
98 $this->currentWorkspace = $currentWorkspace;
99 } else {
100 throw new \InvalidArgumentException('No such workspace defined');
101 }
102 $data = array();
103 $data['data'] = array();
104 $this->generateDataArray($versions, $filterTxt);
105 $data['total'] = count($this->dataArray);
106 $data['data'] = $this->getDataArray($start, $limit);
107 return $data;
108 }
109
110 /**
111 * Generates grid list array from given versions.
112 *
113 * @param array $versions All available version records
114 * @param string $filterTxt Text to be used to filter record result
115 * @return void
116 */
117 protected function generateDataArray(array $versions, $filterTxt) {
118 $workspaceAccess = $GLOBALS['BE_USER']->checkWorkspace($GLOBALS['BE_USER']->workspace);
119 $swapStage = $workspaceAccess['publish_access'] & 1 ? \TYPO3\CMS\Workspaces\Service\StagesService::STAGE_PUBLISH_ID : 0;
120 $swapAccess = $GLOBALS['BE_USER']->workspacePublishAccess($GLOBALS['BE_USER']->workspace) && $GLOBALS['BE_USER']->workspaceSwapAccess();
121 $this->initializeWorkspacesCachingFramework();
122 // check for dataArray in cache
123 if ($this->getDataArrayFromCache($versions, $filterTxt) === FALSE) {
124 /** @var $stagesObj \TYPO3\CMS\Workspaces\Service\StagesService */
125 $stagesObj = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\StagesService::class);
126 $defaultGridColumns = array(
127 self::GridColumn_Collection => 0,
128 self::GridColumn_CollectionLevel => 0,
129 self::GridColumn_CollectionParent => '',
130 self::GridColumn_CollectionCurrent => '',
131 self::GridColumn_CollectionChildren => 0,
132 );
133 foreach ($versions as $table => $records) {
134 $hiddenField = $this->getTcaEnableColumnsFieldName($table, 'disabled');
135 $isRecordTypeAllowedToModify = $GLOBALS['BE_USER']->check('tables_modify', $table);
136
137 foreach ($records as $record) {
138 $origRecord = BackendUtility::getRecord($table, $record['t3ver_oid']);
139 $versionRecord = BackendUtility::getRecord($table, $record['uid']);
140 $combinedRecord = \TYPO3\CMS\Workspaces\Domain\Model\CombinedRecord::createFromArrays($table, $origRecord, $versionRecord);
141 $this->getIntegrityService()->checkElement($combinedRecord);
142
143 if ($hiddenField !== NULL) {
144 $recordState = $this->workspaceState($versionRecord['t3ver_state'], $origRecord[$hiddenField], $versionRecord[$hiddenField]);
145 } else {
146 $recordState = $this->workspaceState($versionRecord['t3ver_state']);
147 }
148
149 $isDeletedPage = $table == 'pages' && $recordState == 'deleted';
150 $viewUrl = \TYPO3\CMS\Workspaces\Service\WorkspaceService::viewSingleRecord($table, $record['uid'], $origRecord, $versionRecord);
151 $versionArray = array();
152 $versionArray['table'] = $table;
153 $versionArray['id'] = $table . ':' . $record['uid'];
154 $versionArray['uid'] = $record['uid'];
155 $versionArray['workspace'] = $versionRecord['t3ver_id'];
156 $versionArray = array_merge($versionArray, $defaultGridColumns);
157 $versionArray['label_Workspace'] = htmlspecialchars(BackendUtility::getRecordTitle($table, $versionRecord));
158 $versionArray['label_Live'] = htmlspecialchars(BackendUtility::getRecordTitle($table, $origRecord));
159 $versionArray['label_Stage'] = htmlspecialchars($stagesObj->getStageTitle($versionRecord['t3ver_stage']));
160 $tempStage = $stagesObj->getNextStage($versionRecord['t3ver_stage']);
161 $versionArray['label_nextStage'] = htmlspecialchars($stagesObj->getStageTitle($tempStage['uid']));
162 $tempStage = $stagesObj->getPrevStage($versionRecord['t3ver_stage']);
163 $versionArray['label_prevStage'] = htmlspecialchars($stagesObj->getStageTitle($tempStage['uid']));
164 $versionArray['path_Live'] = htmlspecialchars(BackendUtility::getRecordPath($record['livepid'], '', 999));
165 $versionArray['path_Workspace'] = htmlspecialchars(BackendUtility::getRecordPath($record['wspid'], '', 999));
166 $versionArray['workspace_Title'] = htmlspecialchars(\TYPO3\CMS\Workspaces\Service\WorkspaceService::getWorkspaceTitle($versionRecord['t3ver_wsid']));
167 $versionArray['workspace_Tstamp'] = $versionRecord['tstamp'];
168 $versionArray['workspace_Formated_Tstamp'] = BackendUtility::datetime($versionRecord['tstamp']);
169 $versionArray['t3ver_wsid'] = $versionRecord['t3ver_wsid'];
170 $versionArray['t3ver_oid'] = $record['t3ver_oid'];
171 $versionArray['livepid'] = $record['livepid'];
172 $versionArray['stage'] = $versionRecord['t3ver_stage'];
173 $versionArray['icon_Live'] = \TYPO3\CMS\Backend\Utility\IconUtility::mapRecordTypeToSpriteIconClass($table, $origRecord);
174 $versionArray['icon_Workspace'] = \TYPO3\CMS\Backend\Utility\IconUtility::mapRecordTypeToSpriteIconClass($table, $versionRecord);
175 $languageValue = $this->getLanguageValue($table, $versionRecord);
176 $versionArray['languageValue'] = $languageValue;
177 $versionArray['language'] = array(
178 'cls' => \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconClasses($this->getSystemLanguageValue($languageValue, 'flagIcon')),
179 'title' => htmlspecialchars($this->getSystemLanguageValue($languageValue, 'title'))
180 );
181 $versionArray['allowedAction_nextStage'] = $isRecordTypeAllowedToModify && $stagesObj->isNextStageAllowedForUser($versionRecord['t3ver_stage']);
182 $versionArray['allowedAction_prevStage'] = $isRecordTypeAllowedToModify && $stagesObj->isPrevStageAllowedForUser($versionRecord['t3ver_stage']);
183 if ($swapAccess && $swapStage != 0 && $versionRecord['t3ver_stage'] == $swapStage) {
184 $versionArray['allowedAction_swap'] = $isRecordTypeAllowedToModify && $stagesObj->isNextStageAllowedForUser($swapStage);
185 } elseif ($swapAccess && $swapStage == 0) {
186 $versionArray['allowedAction_swap'] = $isRecordTypeAllowedToModify;
187 } else {
188 $versionArray['allowedAction_swap'] = FALSE;
189 }
190 $versionArray['allowedAction_delete'] = $isRecordTypeAllowedToModify;
191 // preview and editing of a deleted page won't work ;)
192 $versionArray['allowedAction_view'] = !$isDeletedPage && $viewUrl;
193 $versionArray['allowedAction_edit'] = $isRecordTypeAllowedToModify && !$isDeletedPage;
194 $versionArray['allowedAction_editVersionedPage'] = $isRecordTypeAllowedToModify && !$isDeletedPage;
195 $versionArray['state_Workspace'] = $recordState;
196
197 $versionArray = array_merge(
198 $versionArray,
199 $this->getAdditionalColumnService()->getData($combinedRecord)
200 );
201
202 if ($filterTxt == '' || $this->isFilterTextInVisibleColumns($filterTxt, $versionArray)) {
203 $versionIdentifier = $versionArray['id'];
204 $this->dataArray[$versionIdentifier] = $versionArray;
205 }
206 }
207 }
208 // Suggested slot method:
209 // methodName(\TYPO3\CMS\Workspaces\Service\GridDataService $gridData, array &$dataArray, array $versions)
210 $this->emitSignal(self::SIGNAL_GenerateDataArray_BeforeCaching, $this->dataArray, $versions);
211 // Enrich elements after everything has been processed:
212 foreach ($this->dataArray as &$element) {
213 $identifier = $element['table'] . ':' . $element['t3ver_oid'];
214 $element['integrity'] = array(
215 'status' => $this->getIntegrityService()->getStatusRepresentation($identifier),
216 'messages' => htmlspecialchars($this->getIntegrityService()->getIssueMessages($identifier, TRUE))
217 );
218 }
219 $this->setDataArrayIntoCache($versions, $filterTxt);
220 }
221 // Suggested slot method:
222 // methodName(\TYPO3\CMS\Workspaces\Service\GridDataService $gridData, array &$dataArray, array $versions)
223 $this->emitSignal(self::SIGNAL_GenerateDataArray_PostProcesss, $this->dataArray, $versions);
224 $this->sortDataArray();
225 $this->resolveDataArrayDependencies();
226 }
227
228 /**
229 * Resolves dependencies of nested structures
230 * and sort data elements considering these dependencies.
231 *
232 * @return void
233 */
234 protected function resolveDataArrayDependencies() {
235 $collectionService = $this->getDependencyCollectionService();
236 $dependencyResolver = $collectionService->getDependencyResolver();
237
238 foreach ($this->dataArray as $dataElement) {
239 $dependencyResolver->addElement($dataElement['table'], $dataElement['uid']);
240 }
241
242 $this->dataArray = $collectionService->process($this->dataArray);
243 }
244
245 /**
246 * Gets the data array by considering the page to be shown in the grid view.
247 *
248 * @param int $start
249 * @param int $limit
250 * @return array
251 */
252 protected function getDataArray($start, $limit) {
253 $dataArrayPart = array();
254 $dataArrayCount = count($this->dataArray);
255 $end = ($start + $limit < count($this->dataArray) ? $start + $limit : $dataArrayCount);
256
257 // Ensure that there are numerical indexes
258 $this->dataArray = array_values(($this->dataArray));
259 for ($i = $start; $i < $end; $i++) {
260 $dataArrayPart[] = $this->dataArray[$i];
261 }
262
263 // Ensure that collections are not cut for the pagination
264 if (!empty($this->dataArray[$i][self::GridColumn_Collection])) {
265 $collectionIdentifier = $this->dataArray[$i][self::GridColumn_Collection];
266 for ($i = $i + 1; $i < $dataArrayCount && $collectionIdentifier === $this->dataArray[$i][self::GridColumn_Collection]; $i++) {
267 $dataArrayPart[] = $this->dataArray[$i];
268 }
269 }
270
271 // Suggested slot method:
272 // methodName(\TYPO3\CMS\Workspaces\Service\GridDataService $gridData, array &$dataArray, $start, $limit)
273 $this->emitSignal(self::SIGNAL_GetDataArray_PostProcesss, $this->dataArray, $start, $limit);
274 return $dataArrayPart;
275 }
276
277 /**
278 * Initializes the workspace cache
279 *
280 * @return void
281 */
282 protected function initializeWorkspacesCachingFramework() {
283 $this->workspacesCache = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->getCache('workspaces_cache');
284 }
285
286 /**
287 * Puts the generated dataArray into the workspace cache.
288 *
289 * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid and t3ver_oid fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid
290 * @param string $filterTxt The given filter text from the grid.
291 */
292 protected function setDataArrayIntoCache(array $versions, $filterTxt) {
293 $hash = $this->calculateHash($versions, $filterTxt);
294 $this->workspacesCache->set($hash, $this->dataArray, array($this->currentWorkspace, 'user_' . $GLOBALS['BE_USER']->user['uid']));
295 }
296
297 /**
298 * Checks if a cache entry is given for given versions and filter text and tries to load the data array from cache.
299 *
300 * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid and t3ver_oid fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid
301 * @param string $filterTxt The given filter text from the grid.
302 * @return bool TRUE if cache entry was successfully fetched from cache and content put to $this->dataArray
303 */
304 protected function getDataArrayFromCache(array $versions, $filterTxt) {
305 $cacheEntry = FALSE;
306 $hash = $this->calculateHash($versions, $filterTxt);
307 $content = $this->workspacesCache->get($hash);
308 if ($content !== FALSE) {
309 $this->dataArray = $content;
310 $cacheEntry = TRUE;
311 }
312 return $cacheEntry;
313 }
314
315 /**
316 * Calculates the hash value of the used workspace, the user id, the versions array, the filter text, the sorting attribute, the workspace selected in grid and the sorting direction.
317 *
318 * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid and t3ver_oid fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid
319 * @param string $filterTxt The given filter text from the grid.
320 * @return string
321 */
322 protected function calculateHash(array $versions, $filterTxt) {
323 $hashArray = array(
324 $GLOBALS['BE_USER']->workspace,
325 $GLOBALS['BE_USER']->user['uid'],
326 $versions,
327 $filterTxt,
328 $this->sort,
329 $this->sortDir,
330 $this->currentWorkspace
331 );
332 $hash = md5(serialize($hashArray));
333 return $hash;
334 }
335
336 /**
337 * Performs sorting on the data array accordant to the
338 * selected column in the grid view to be used for sorting.
339 *
340 * @return void
341 */
342 protected function sortDataArray() {
343 if (is_array($this->dataArray)) {
344 switch ($this->sort) {
345 case 'uid':
346 case 'change':
347 case 'workspace_Tstamp':
348 case 't3ver_oid':
349 case 'liveid':
350 case 'livepid':
351 case 'languageValue':
352 uasort($this->dataArray, array($this, 'intSort'));
353 break;
354 case 'label_Workspace':
355 case 'label_Live':
356 case 'label_Stage':
357 case 'workspace_Title':
358 case 'path_Live':
359 // case 'path_Workspace': This is the first sorting attribute
360 uasort($this->dataArray, array($this, 'stringSort'));
361 break;
362 default:
363 // Do nothing
364 }
365 } else {
366 GeneralUtility::sysLog('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 reproduced yet.', 3);
367 }
368 // Suggested slot method:
369 // methodName(\TYPO3\CMS\Workspaces\Service\GridDataService $gridData, array &$dataArray, $sortColumn, $sortDirection)
370 $this->emitSignal(self::SIGNAL_SortDataArray_PostProcesss, $this->dataArray, $this->sort, $this->sortDir);
371 }
372
373 /**
374 * Implements individual sorting for columns based on integer comparison.
375 *
376 * @param array $a First value
377 * @param array $b Second value
378 * @return int
379 */
380 protected function intSort(array $a, array $b) {
381 if (!$this->isSortable($a, $b)) {
382 return 0;
383 }
384 // First sort by using the page-path in current workspace
385 $path_cmp = strcasecmp($a['path_Workspace'], $b['path_Workspace']);
386 if ($path_cmp < 0) {
387 return $path_cmp;
388 } elseif ($path_cmp == 0) {
389 if ($a[$this->sort] == $b[$this->sort]) {
390 return 0;
391 }
392 if ($this->sortDir == 'ASC') {
393 return $a[$this->sort] < $b[$this->sort] ? -1 : 1;
394 } elseif ($this->sortDir == 'DESC') {
395 return $a[$this->sort] > $b[$this->sort] ? -1 : 1;
396 }
397 } elseif ($path_cmp > 0) {
398 return $path_cmp;
399 }
400 return 0;
401 }
402
403 /**
404 * Implements individual sorting for columns based on string comparison.
405 *
406 * @param string $a First value
407 * @param string $b Second value
408 * @return int
409 */
410 protected function stringSort($a, $b) {
411 if (!$this->isSortable($a, $b)) {
412 return 0;
413 }
414 $path_cmp = strcasecmp($a['path_Workspace'], $b['path_Workspace']);
415 if ($path_cmp < 0) {
416 return $path_cmp;
417 } elseif ($path_cmp == 0) {
418 if ($a[$this->sort] == $b[$this->sort]) {
419 return 0;
420 }
421 if ($this->sortDir == 'ASC') {
422 return strcasecmp($a[$this->sort], $b[$this->sort]);
423 } elseif ($this->sortDir == 'DESC') {
424 return strcasecmp($a[$this->sort], $b[$this->sort]) * -1;
425 }
426 } elseif ($path_cmp > 0) {
427 return $path_cmp;
428 }
429 return 0;
430 }
431
432 /**
433 * Determines whether dataArray elements are sortable.
434 * Only elements on the first level (0) or below the same
435 * parent element are directly sortable.
436 *
437 * @param array $a
438 * @param array $b
439 * @return bool
440 */
441 protected function isSortable(array $a, array $b) {
442 return (
443 $a[self::GridColumn_CollectionLevel] === 0 && $b[self::GridColumn_CollectionLevel] === 0
444 || $a[self::GridColumn_CollectionParent] === $b[self::GridColumn_CollectionParent]
445 );
446 }
447
448 /**
449 * Determines whether the text used to filter the results is part of
450 * a column that is visible in the grid view.
451 *
452 * @param string $filterText
453 * @param array $versionArray
454 * @return bool
455 */
456 protected function isFilterTextInVisibleColumns($filterText, array $versionArray) {
457 if (is_array($GLOBALS['BE_USER']->uc['moduleData']['Workspaces'][$GLOBALS['BE_USER']->workspace]['columns'])) {
458 foreach ($GLOBALS['BE_USER']->uc['moduleData']['Workspaces'][$GLOBALS['BE_USER']->workspace]['columns'] as $column => $value) {
459 if (isset($value['hidden']) && isset($column) && isset($versionArray[$column])) {
460 if ($value['hidden'] == 0) {
461 switch ($column) {
462 case 'workspace_Tstamp':
463 if (stripos($versionArray['workspace_Formated_Tstamp'], $filterText) !== FALSE) {
464 return TRUE;
465 }
466 break;
467 case 'change':
468 if (stripos(strval($versionArray[$column]), str_replace('%', '', $filterText)) !== FALSE) {
469 return TRUE;
470 }
471 break;
472 default:
473 if (stripos(strval($versionArray[$column]), $filterText) !== FALSE) {
474 return TRUE;
475 }
476 }
477 }
478 }
479 }
480 }
481 return FALSE;
482 }
483
484 /**
485 * Gets the state of a given state value.
486 *
487 * @param int $stateId stateId of offline record
488 * @param bool $hiddenOnline hidden status of online record
489 * @param bool $hiddenOffline hidden status of offline record
490 * @return string
491 */
492 protected function workspaceState($stateId, $hiddenOnline = FALSE, $hiddenOffline = FALSE) {
493 $hiddenState = NULL;
494 if ($hiddenOnline == 0 && $hiddenOffline == 1) {
495 $hiddenState = 'hidden';
496 } elseif ($hiddenOnline == 1 && $hiddenOffline == 0) {
497 $hiddenState = 'unhidden';
498 }
499 switch ($stateId) {
500 case -1:
501 $state = 'new';
502 break;
503 case 2:
504 $state = 'deleted';
505 break;
506 case 4:
507 $state = 'moved';
508 break;
509 default:
510 $state = ($hiddenState ?: 'modified');
511 }
512 return $state;
513 }
514
515 /**
516 * Gets the field name of the enable-columns as defined in $TCA.
517 *
518 * @param string $table Name of the table
519 * @param string $type Type to be fetches (e.g. 'disabled', 'starttime', 'endtime', 'fe_group)
520 * @return string|NULL The accordant field name or NULL if not defined
521 */
522 protected function getTcaEnableColumnsFieldName($table, $type) {
523 $fieldName = NULL;
524
525 if (!(empty($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'][$type]))) {
526 $fieldName = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns'][$type];
527 }
528
529 return $fieldName;
530 }
531
532 /**
533 * Gets the used language value (sys_language.uid) of
534 * a given database record.
535 *
536 * @param string $table Name of the table
537 * @param array $record Database record
538 * @return int
539 */
540 protected function getLanguageValue($table, array $record) {
541 $languageValue = 0;
542 if (BackendUtility::isTableLocalizable($table)) {
543 $languageField = $GLOBALS['TCA'][$table]['ctrl']['languageField'];
544 if (!empty($record[$languageField])) {
545 $languageValue = $record[$languageField];
546 }
547 }
548 return $languageValue;
549 }
550
551 /**
552 * Gets a named value of the available sys_language elements.
553 *
554 * @param int $id sys_language uid
555 * @param string $key Name of the value to be fetched (e.g. title)
556 * @return string|NULL
557 * @see getSystemLanguages
558 */
559 protected function getSystemLanguageValue($id, $key) {
560 $value = NULL;
561 $systemLanguages = $this->getSystemLanguages();
562 if (!empty($systemLanguages[$id][$key])) {
563 $value = $systemLanguages[$id][$key];
564 }
565 return $value;
566 }
567
568 /**
569 * Gets all available system languages.
570 *
571 * @return array
572 */
573 public function getSystemLanguages() {
574 if (!isset($this->systemLanguages)) {
575 /** @var $translateTools \TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider */
576 $translateTools = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider::class);
577 $this->systemLanguages = $translateTools->getSystemLanguages();
578 }
579 return $this->systemLanguages;
580 }
581
582 /**
583 * Gets an instance of the integrity service.
584 *
585 * @return \TYPO3\CMS\Workspaces\Service\IntegrityService
586 */
587 protected function getIntegrityService() {
588 if (!isset($this->integrityService)) {
589 $this->integrityService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\IntegrityService::class);
590 }
591 return $this->integrityService;
592 }
593
594 /**
595 * Emits a signal to be handled by any registered slots.
596 *
597 * @param string $signalName Name of the signal
598 * @return void
599 */
600 protected function emitSignal($signalName) {
601 // Arguments are always ($this, [method argument], [method argument], ...)
602 $signalArguments = array_merge(array($this), array_slice(func_get_args(), 1));
603 $this->getSignalSlotDispatcher()->dispatch(\TYPO3\CMS\Workspaces\Service\GridDataService::class, $signalName, $signalArguments);
604 }
605
606 /**
607 * @return \TYPO3\CMS\Workspaces\Service\Dependency\CollectionService
608 */
609 protected function getDependencyCollectionService() {
610 return GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\Dependency\CollectionService::class);
611 }
612
613 /**
614 * @return \TYPO3\CMS\Workspaces\Service\AdditionalColumnService
615 */
616 protected function getAdditionalColumnService() {
617 return $this->getObjectManager()->get(\TYPO3\CMS\Workspaces\Service\AdditionalColumnService::class);
618 }
619
620 /**
621 * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
622 */
623 protected function getSignalSlotDispatcher() {
624 return $this->getObjectManager()->get(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
625 }
626
627 /**
628 * @return \TYPO3\CMS\Extbase\Object\ObjectManager
629 */
630 protected function getObjectManager() {
631 return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
632 }
633
634 }