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