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