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