[TASK] Cleanup and deprecate TYPO3_DB occurrences
[Packages/TYPO3.CMS.git] / typo3 / sysext / workspaces / Classes / Service / StagesService.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\Database\ConnectionPool;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Core\Utility\MathUtility;
21 use TYPO3\CMS\Workspaces\Domain\Record\StageRecord;
22 use TYPO3\CMS\Workspaces\Domain\Record\WorkspaceRecord;
23
24 /**
25 * Stages service
26 */
27 class StagesService implements \TYPO3\CMS\Core\SingletonInterface
28 {
29 const TABLE_STAGE = 'sys_workspace_stage';
30 // if a record is in the "ready to publish" stage STAGE_PUBLISH_ID the nextStage is STAGE_PUBLISH_EXECUTE_ID, this id wont be saved at any time in db
31 const STAGE_PUBLISH_EXECUTE_ID = -20;
32 // ready to publish stage
33 const STAGE_PUBLISH_ID = -10;
34 const STAGE_EDIT_ID = 0;
35 const MODE_NOTIFY_SOMEONE = 0;
36 const MODE_NOTIFY_ALL = 1;
37 const MODE_NOTIFY_ALL_STRICT = 2;
38
39 /**
40 * Path to the locallang file
41 *
42 * @var string
43 */
44 private $pathToLocallang = 'LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf';
45
46 /**
47 * @var RecordService
48 */
49 protected $recordService;
50
51 /**
52 * Local cache to reduce number of database queries for stages, groups, etc.
53 *
54 * @var array
55 */
56 protected $workspaceStageCache = [];
57
58 /**
59 * @var array
60 */
61 protected $workspaceStageAllowedCache = [];
62
63 /**
64 * @var array
65 */
66 protected $fetchGroupsCache = [];
67
68 /**
69 * @var array
70 */
71 protected $userGroups = [];
72
73 /**
74 * Getter for current workspace id
75 *
76 * @return int Current workspace id
77 */
78 public function getWorkspaceId()
79 {
80 return $this->getBackendUser()->workspace;
81 }
82
83 /**
84 * Find the highest possible "previous" stage for all $byTableName
85 *
86 * @param array $workspaceItems
87 * @param array $byTableName
88 * @return array Current and next highest possible stage
89 */
90 public function getPreviousStageForElementCollection(
91 $workspaceItems,
92 array $byTableName = ['tt_content', 'pages', 'pages_language_overlay']
93 ) {
94 $currentStage = [];
95 $previousStage = [];
96 $usedStages = [];
97 $found = false;
98 $availableStagesForWS = array_reverse($this->getStagesForWS());
99 $availableStagesForWSUser = $this->getStagesForWSUser();
100 $byTableName = array_flip($byTableName);
101 foreach ($workspaceItems as $tableName => $items) {
102 if (!array_key_exists($tableName, $byTableName)) {
103 continue;
104 }
105 foreach ($items as $item) {
106 $usedStages[$item['t3ver_stage']] = true;
107 }
108 }
109 foreach ($availableStagesForWS as $stage) {
110 if (isset($usedStages[$stage['uid']])) {
111 $currentStage = $stage;
112 $previousStage = $this->getPrevStage($stage['uid']);
113 break;
114 }
115 }
116 foreach ($availableStagesForWSUser as $userWS) {
117 if ($previousStage['uid'] == $userWS['uid']) {
118 $found = true;
119 break;
120 }
121 }
122 if ($found === false || !$this->isStageAllowedForUser($currentStage['uid'])) {
123 $previousStage = [];
124 }
125 return [
126 $currentStage,
127 $previousStage
128 ];
129 }
130
131 /**
132 * Retrieve the next stage based on the lowest stage given in the $workspaceItems record array.
133 *
134 * @param array $workspaceItems
135 * @param array $byTableName
136 * @return array Current and next possible stage.
137 */
138 public function getNextStageForElementCollection(
139 $workspaceItems,
140 array $byTableName = ['tt_content', 'pages', 'pages_language_overlay']
141 ) {
142 $currentStage = [];
143 $usedStages = [];
144 $nextStage = [];
145 $availableStagesForWS = $this->getStagesForWS();
146 $availableStagesForWSUser = $this->getStagesForWSUser();
147 $byTableName = array_flip($byTableName);
148 $found = false;
149 foreach ($workspaceItems as $tableName => $items) {
150 if (!array_key_exists($tableName, $byTableName)) {
151 continue;
152 }
153 foreach ($items as $item) {
154 $usedStages[$item['t3ver_stage']] = true;
155 }
156 }
157 foreach ($availableStagesForWS as $stage) {
158 if (isset($usedStages[$stage['uid']])) {
159 $currentStage = $stage;
160 $nextStage = $this->getNextStage($stage['uid']);
161 break;
162 }
163 }
164 foreach ($availableStagesForWSUser as $userWS) {
165 if ($nextStage['uid'] == $userWS['uid']) {
166 $found = true;
167 break;
168 }
169 }
170 if ($found === false || !$this->isStageAllowedForUser($currentStage['uid'])) {
171 $nextStage = [];
172 }
173 return [
174 $currentStage,
175 $nextStage
176 ];
177 }
178
179 /**
180 * Building an array with all stage ids and titles related to the given workspace
181 *
182 * @return array id and title of the stages
183 */
184 public function getStagesForWS()
185 {
186 if (isset($this->workspaceStageCache[$this->getWorkspaceId()])) {
187 $stages = $this->workspaceStageCache[$this->getWorkspaceId()];
188 } elseif ($this->getWorkspaceId() === 0) {
189 $stages = [];
190 } else {
191 $stages = $this->prepareStagesArray($this->getWorkspaceRecord()->getStages());
192 $this->workspaceStageCache[$this->getWorkspaceId()] = $stages;
193 }
194 return $stages;
195 }
196
197 /**
198 * Returns an array of stages, the user is allowed to send to
199 *
200 * @return array id and title of stages
201 */
202 public function getStagesForWSUser()
203 {
204 if ($GLOBALS['BE_USER']->isAdmin()) {
205 return $this->getStagesForWS();
206 }
207
208 /** @var $allowedStages StageRecord[] */
209 $allowedStages = [];
210 $stageRecords = $this->getWorkspaceRecord()->getStages();
211
212 // Only use stages that are allowed for current backend user
213 foreach ($stageRecords as $stageRecord) {
214 if ($stageRecord->isAllowed()) {
215 $allowedStages[$stageRecord->getUid()] = $stageRecord;
216 }
217 }
218
219 // Add previous and next stages (even if they are not allowed!)
220 foreach ($allowedStages as $allowedStage) {
221 $previousStage = $allowedStage->getPrevious();
222 $nextStage = $allowedStage->getNext();
223 if ($previousStage !== null && !isset($allowedStages[$previousStage->getUid()])) {
224 $allowedStages[$previousStage->getUid()] = $previousStage;
225 }
226 if ($nextStage !== null && !isset($allowedStages[$nextStage->getUid()])) {
227 $allowedStages[$nextStage->getUid()] = $nextStage;
228 }
229 }
230
231 uasort($allowedStages, function (StageRecord $first, StageRecord $second) {
232 return $first->determineOrder($second);
233 });
234 return $this->prepareStagesArray($allowedStages);
235 }
236
237 /**
238 * Prepares simplified stages array to be used in ExtJs components.
239 *
240 * @param StageRecord[] $stageRecords
241 * @return array
242 */
243 protected function prepareStagesArray(array $stageRecords)
244 {
245 $stagesArray = [];
246 foreach ($stageRecords as $stageRecord) {
247 $stage = [
248 'uid' => $stageRecord->getUid(),
249 'label' => $stageRecord->getTitle(),
250 ];
251 if (!$stageRecord->isExecuteStage()) {
252 $stage['title'] = $GLOBALS['LANG']->sL(($this->pathToLocallang . ':actionSendToStage')) . ' "' . $stageRecord->getTitle() . '"';
253 } else {
254 $stage['title'] = $GLOBALS['LANG']->sL($this->pathToLocallang . ':publish_execute_action_option');
255 }
256 $stagesArray[] = $stage;
257 }
258 return $stagesArray;
259 }
260
261 /**
262 * Gets the title of a stage.
263 *
264 * @param int $ver_stage
265 * @return string
266 */
267 public function getStageTitle($ver_stage)
268 {
269 switch ($ver_stage) {
270 case self::STAGE_PUBLISH_EXECUTE_ID:
271 $stageTitle = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_user_ws.xlf:stage_publish');
272 break;
273 case self::STAGE_PUBLISH_ID:
274 $stageTitle = $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang_mod.xlf:stage_ready_to_publish');
275 break;
276 case self::STAGE_EDIT_ID:
277 $stageTitle = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_user_ws.xlf:stage_editing');
278 break;
279 default:
280 $stageTitle = $this->getPropertyOfCurrentWorkspaceStage($ver_stage, 'title');
281 if ($stageTitle == null) {
282 $stageTitle = $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:error.getStageTitle.stageNotFound');
283 }
284 }
285 return $stageTitle;
286 }
287
288 /**
289 * Gets a particular stage record.
290 *
291 * @param int $stageid
292 * @return array
293 */
294 public function getStageRecord($stageid)
295 {
296 return BackendUtility::getRecord('sys_workspace_stage', $stageid);
297 }
298
299 /**
300 * Gets next stage in process for given stage id
301 *
302 * @param int $stageId Id of the stage to fetch the next one for
303 * @return int The next stage Id
304 * @throws \InvalidArgumentException
305 */
306 public function getNextStage($stageId)
307 {
308 if (!MathUtility::canBeInterpretedAsInteger($stageId)) {
309 throw new \InvalidArgumentException(
310 $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:error.stageId.integer'),
311 1291109987
312 );
313 }
314 $nextStage = false;
315 $workspaceStageRecs = $this->getStagesForWS();
316 if (is_array($workspaceStageRecs) && !empty($workspaceStageRecs)) {
317 reset($workspaceStageRecs);
318 while (!is_null(($workspaceStageRecKey = key($workspaceStageRecs)))) {
319 $workspaceStageRec = current($workspaceStageRecs);
320 if ($workspaceStageRec['uid'] == $stageId) {
321 $nextStage = next($workspaceStageRecs);
322 break;
323 }
324 next($workspaceStageRecs);
325 }
326 }
327 if ($nextStage === false) {
328 $nextStage[] = [
329 'uid' => self::STAGE_EDIT_ID,
330 'title' => $GLOBALS['LANG']->sL(($this->pathToLocallang . ':actionSendToStage')) . ' "'
331 . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_user_ws.xlf:stage_editing') . '"'
332 ];
333 }
334 return $nextStage;
335 }
336
337 /**
338 * Recursive function to get all next stages for a record depending on user permissions
339 *
340 * @param array $nextStageArray Next stages
341 * @param int $stageId Current stage id of the record
342 * @return array Next stages
343 */
344 public function getNextStages(array &$nextStageArray, $stageId)
345 {
346 // Current stage is "Ready to publish" - there is no next stage
347 if ($stageId == self::STAGE_PUBLISH_ID) {
348 return $nextStageArray;
349 } else {
350 $nextStageRecord = $this->getNextStage($stageId);
351 if (empty($nextStageRecord) || !is_array($nextStageRecord)) {
352 // There is no next stage
353 return $nextStageArray;
354 } else {
355 // Check if the user has the permission to for the current stage
356 // If this next stage record is the first next stage after the current the user
357 // has always the needed permission
358 if ($this->isStageAllowedForUser($stageId)) {
359 $nextStageArray[] = $nextStageRecord;
360 return $this->getNextStages($nextStageArray, $nextStageRecord['uid']);
361 } else {
362 // He hasn't - return given next stage array
363 return $nextStageArray;
364 }
365 }
366 }
367 }
368
369 /**
370 * Get next stage in process for given stage id
371 *
372 * @param int $stageId Id of the stage to fetch the previous one for
373 * @return int The previous stage Id
374 * @throws \InvalidArgumentException
375 */
376 public function getPrevStage($stageId)
377 {
378 if (!MathUtility::canBeInterpretedAsInteger($stageId)) {
379 throw new \InvalidArgumentException(
380 $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:error.stageId.integer'),
381 1476048351
382 );
383 }
384 $prevStage = false;
385 $workspaceStageRecs = $this->getStagesForWS();
386 if (is_array($workspaceStageRecs) && !empty($workspaceStageRecs)) {
387 end($workspaceStageRecs);
388 while (!is_null(($workspaceStageRecKey = key($workspaceStageRecs)))) {
389 $workspaceStageRec = current($workspaceStageRecs);
390 if ($workspaceStageRec['uid'] == $stageId) {
391 $prevStage = prev($workspaceStageRecs);
392 break;
393 }
394 prev($workspaceStageRecs);
395 }
396 } else {
397 }
398 return $prevStage;
399 }
400
401 /**
402 * Recursive function to get all prev stages for a record depending on user permissions
403 *
404 * @param array $prevStageArray Prev stages
405 * @param int $stageId Current stage id of the record
406 * @return array prev stages
407 */
408 public function getPrevStages(array &$prevStageArray, $stageId)
409 {
410 // Current stage is "Editing" - there is no prev stage
411 if ($stageId != self::STAGE_EDIT_ID) {
412 $prevStageRecord = $this->getPrevStage($stageId);
413 if (!empty($prevStageRecord) && is_array($prevStageRecord)) {
414 // Check if the user has the permission to switch to that stage
415 // If this prev stage record is the first previous stage before the current
416 // the user has always the needed permission
417 if ($this->isStageAllowedForUser($stageId)) {
418 $prevStageArray[] = $prevStageRecord;
419 $prevStageArray = $this->getPrevStages($prevStageArray, $prevStageRecord['uid']);
420 }
421 }
422 }
423 return $prevStageArray;
424 }
425
426 /**
427 * Gets all backend user records that are considered to be responsible
428 * for a particular stage or workspace.
429 *
430 * @param StageRecord|int $stageRecord Stage
431 * @param bool $selectDefaultUserField If field notification_defaults should be selected instead of responsible users
432 * @return array be_users with e-mail and name
433 */
434 public function getResponsibleBeUser($stageRecord, $selectDefaultUserField = false)
435 {
436 if (!$stageRecord instanceof StageRecord) {
437 $stageRecord = $this->getWorkspaceRecord()->getStage($stageRecord);
438 }
439
440 $recipientArray = [];
441
442 if (!$selectDefaultUserField) {
443 $backendUserIds = $stageRecord->getAllRecipients();
444 } else {
445 $backendUserIds = $stageRecord->getDefaultRecipients();
446 }
447
448 $userList = implode(',', $backendUserIds);
449 $userRecords = $this->getBackendUsers($userList);
450 foreach ($userRecords as $userUid => $userRecord) {
451 $recipientArray[$userUid] = $userRecord;
452 }
453 return $recipientArray;
454 }
455
456 /**
457 * Gets backend user ids from a mixed list of backend users
458 * and backend users groups. This is used for notifying persons
459 * responsible for a particular stage or workspace.
460 *
461 * @param string $stageRespValue Responsible_person value from stage record
462 * @return string List of backend user ids
463 */
464 public function getResponsibleUser($stageRespValue)
465 {
466 return implode(',', $this->resolveBackendUserIds($stageRespValue));
467 }
468
469 /**
470 * Resolves backend user ids from a mixed list of backend users
471 * and backend user groups (e.g. "be_users_1,be_groups_3,be_users_4,...")
472 *
473 * @param string $backendUserGroupList
474 * @return array
475 */
476 public function resolveBackendUserIds($backendUserGroupList)
477 {
478 $elements = GeneralUtility::trimExplode(',', $backendUserGroupList, true);
479 $backendUserIds = [];
480 $backendGroupIds = [];
481
482 foreach ($elements as $element) {
483 if (strpos($element, 'be_users_') === 0) {
484 // Current value is a uid of a be_user record
485 $backendUserIds[] = str_replace('be_users_', '', $element);
486 } elseif (strpos($element, 'be_groups_') === 0) {
487 $backendGroupIds[] = str_replace('be_groups_', '', $element);
488 } elseif ((int)$element) {
489 $backendUserIds[] = (int)$element;
490 }
491 }
492
493 if (!empty($backendGroupIds)) {
494 $allBeUserArray = BackendUtility::getUserNames();
495 $backendGroupList = implode(',', $backendGroupIds);
496 $this->userGroups = [];
497 $backendGroups = $this->fetchGroups($backendGroupList);
498 foreach ($backendGroups as $backendGroup) {
499 foreach ($allBeUserArray as $backendUserId => $backendUser) {
500 if (GeneralUtility::inList($backendUser['usergroup_cached_list'], $backendGroup['uid'])) {
501 $backendUserIds[] = $backendUserId;
502 }
503 }
504 }
505 }
506
507 return array_unique($backendUserIds);
508 }
509
510 /**
511 * Gets backend user records from a given list of ids.
512 *
513 * @param string $backendUserList
514 * @return array
515 */
516 public function getBackendUsers($backendUserList)
517 {
518 if (empty($backendUserList)) {
519 return [];
520 }
521
522 $backendUserList = implode(',', GeneralUtility::intExplode(',', $backendUserList));
523 $backendUsers = BackendUtility::getUserNames(
524 'username, uid, email, realName',
525 'AND uid IN (' . $backendUserList . ')' . BackendUtility::BEenableFields('be_users')
526 );
527
528 if (empty($backendUsers)) {
529 $backendUsers = [];
530 }
531 return $backendUsers;
532 }
533
534 /**
535 * @param StageRecord $stageRecord
536 * @return array
537 */
538 public function getPreselectedRecipients(StageRecord $stageRecord)
539 {
540 if ($stageRecord->areEditorsPreselected()) {
541 return array_merge(
542 $stageRecord->getPreselectedRecipients(),
543 $this->getRecordService()->getCreateUserIds()
544 );
545 } else {
546 return $stageRecord->getPreselectedRecipients();
547 }
548 }
549
550 /**
551 * @return WorkspaceRecord
552 */
553 protected function getWorkspaceRecord()
554 {
555 return WorkspaceRecord::get($this->getWorkspaceId());
556 }
557
558 /**
559 * @param $grList
560 * @param string $idList
561 * @return array
562 */
563 private function fetchGroups($grList, $idList = '')
564 {
565 $cacheKey = md5($grList . $idList);
566 $groupList = [];
567 if (isset($this->fetchGroupsCache[$cacheKey])) {
568 $groupList = $this->fetchGroupsCache[$cacheKey];
569 } else {
570 if ($idList === '') {
571 // we're at the beginning of the recursion and therefore we need to reset the userGroups member
572 $this->userGroups = [];
573 }
574 $groupList = $this->fetchGroupsRecursive($grList);
575 $this->fetchGroupsCache[$cacheKey] = $groupList;
576 }
577 return $groupList;
578 }
579
580 /**
581 * @param array $groups
582 * @return void
583 */
584 private function fetchGroupsFromDB(array $groups)
585 {
586 // The userGroups array is filled
587 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('be_groups');
588
589 $result = $queryBuilder
590 ->select('*')
591 ->from('be_groups')
592 ->where($queryBuilder->expr()->in('uid', array_map('intval', $groups)))
593 ->execute();
594
595 while ($row = $result->fetch()) {
596 $this->userGroups[$row['uid']] = $row;
597 }
598 }
599
600 /**
601 * Fetches particular groups recursively.
602 *
603 * @param $grList
604 * @param string $idList
605 * @return array
606 */
607 private function fetchGroupsRecursive($grList, $idList = '')
608 {
609 $requiredGroups = GeneralUtility::intExplode(',', $grList, true);
610 $existingGroups = array_keys($this->userGroups);
611 $missingGroups = array_diff($requiredGroups, $existingGroups);
612 if (!empty($missingGroups)) {
613 $this->fetchGroupsFromDB($missingGroups);
614 }
615 // Traversing records in the correct order
616 foreach ($requiredGroups as $uid) {
617 // traversing list
618 // Get row:
619 $row = $this->userGroups[$uid];
620 if (is_array($row) && !GeneralUtility::inList($idList, $uid)) {
621 // Must be an array and $uid should not be in the idList, because then it is somewhere previously in the grouplist
622 // If the localconf.php option isset the user of the sub- sub- groups will also be used
623 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['customStageShowRecipientRecursive'] == 1) {
624 // Include sub groups
625 if (trim($row['subgroup'])) {
626 // Make integer list
627 $theList = implode(',', GeneralUtility::intExplode(',', $row['subgroup']));
628 // Get the subarray
629 $subbarray = $this->fetchGroups($theList, $idList . ',' . $uid);
630 list($subUid, $subArray) = each($subbarray);
631 // Merge the subarray to the already existing userGroups array
632 $this->userGroups[$subUid] = $subArray;
633 }
634 }
635 }
636 }
637 return $this->userGroups;
638 }
639
640 /**
641 * Gets a property of a workspaces stage.
642 *
643 * @param int $stageId
644 * @param string $property
645 * @return string
646 * @throws \InvalidArgumentException
647 */
648 public function getPropertyOfCurrentWorkspaceStage($stageId, $property)
649 {
650 $result = null;
651 if (!MathUtility::canBeInterpretedAsInteger($stageId)) {
652 throw new \InvalidArgumentException(
653 $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:error.stageId.integer'),
654 1476048371
655 );
656 }
657 $workspaceStage = BackendUtility::getRecord(self::TABLE_STAGE, $stageId);
658 if (is_array($workspaceStage) && isset($workspaceStage[$property])) {
659 $result = $workspaceStage[$property];
660 }
661 return $result;
662 }
663
664 /**
665 * Gets the position of the given workspace in the hole process
666 * f.e. 3 means step 3 of 20, by which 1 is edit and 20 is ready to publish
667 *
668 * @param int $stageId
669 * @return array position => 3, count => 20
670 */
671 public function getPositionOfCurrentStage($stageId)
672 {
673 $stagesOfWS = $this->getStagesForWS();
674 $countOfStages = count($stagesOfWS);
675 switch ($stageId) {
676 case self::STAGE_PUBLISH_ID:
677 $position = $countOfStages;
678 break;
679 case self::STAGE_EDIT_ID:
680 $position = 1;
681 break;
682 default:
683 $position = 1;
684 foreach ($stagesOfWS as $key => $stageInfoArray) {
685 $position++;
686 if ($stageId == $stageInfoArray['uid']) {
687 break;
688 }
689 }
690 }
691 return ['position' => $position, 'count' => $countOfStages];
692 }
693
694 /**
695 * Check if the user has access to the previous stage, relative to the given stage
696 *
697 * @param int $stageId
698 * @return bool
699 */
700 public function isPrevStageAllowedForUser($stageId)
701 {
702 $isAllowed = false;
703 try {
704 $prevStage = $this->getPrevStage($stageId);
705 // if there's no prev-stage the stageIds match,
706 // otherwise we've to check if the user is permitted to use the stage
707 if (!empty($prevStage) && $prevStage['uid'] != $stageId) {
708 // if the current stage is allowed for the user, the user is also allowed to send to prev
709 $isAllowed = $this->isStageAllowedForUser($stageId);
710 }
711 } catch (\Exception $e) {
712 }
713 return $isAllowed;
714 }
715
716 /**
717 * Check if the user has access to the next stage, relative to the given stage
718 *
719 * @param int $stageId
720 * @return bool
721 */
722 public function isNextStageAllowedForUser($stageId)
723 {
724 $isAllowed = false;
725 try {
726 $nextStage = $this->getNextStage($stageId);
727 // if there's no next-stage the stageIds match,
728 // otherwise we've to check if the user is permitted to use the stage
729 if (!empty($nextStage) && $nextStage['uid'] != $stageId) {
730 // if the current stage is allowed for the user, the user is also allowed to send to next
731 $isAllowed = $this->isStageAllowedForUser($stageId);
732 }
733 } catch (\Exception $e) {
734 }
735 return $isAllowed;
736 }
737
738 /**
739 * @param $stageId
740 * @return bool
741 */
742 protected function isStageAllowedForUser($stageId)
743 {
744 $cacheKey = $this->getWorkspaceId() . '_' . $stageId;
745 $isAllowed = false;
746 if (isset($this->workspaceStageAllowedCache[$cacheKey])) {
747 $isAllowed = $this->workspaceStageAllowedCache[$cacheKey];
748 } else {
749 $isAllowed = $GLOBALS['BE_USER']->workspaceCheckStageForCurrent($stageId);
750 $this->workspaceStageAllowedCache[$cacheKey] = $isAllowed;
751 }
752 return $isAllowed;
753 }
754
755 /**
756 * Determines whether a stage Id is valid.
757 *
758 * @param int $stageId The stage Id to be checked
759 * @return bool
760 */
761 public function isValid($stageId)
762 {
763 $isValid = false;
764 $stages = $this->getStagesForWS();
765 foreach ($stages as $stage) {
766 if ($stage['uid'] == $stageId) {
767 $isValid = true;
768 break;
769 }
770 }
771 return $isValid;
772 }
773
774 /**
775 * @return RecordService
776 */
777 public function getRecordService()
778 {
779 if (!isset($this->recordService)) {
780 $this->recordService = GeneralUtility::makeInstance(RecordService::class);
781 }
782 return $this->recordService;
783 }
784
785 /**
786 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
787 */
788 protected function getBackendUser()
789 {
790 return $GLOBALS['BE_USER'];
791 }
792 }