‪TYPO3CMS  ‪main
StagesService.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
28 
33 {
34  public const ‪TABLE_STAGE = 'sys_workspace_stage';
35  // 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
36  public const ‪STAGE_PUBLISH_EXECUTE_ID = -20;
37  // ready to publish stage
38  public const ‪STAGE_PUBLISH_ID = -10;
39  public const ‪STAGE_EDIT_ID = 0;
40 
41  private string ‪$pathToLocallang = 'LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf';
42 
44 
48  protected array ‪$workspaceStageCache = [];
49  protected array ‪$workspaceStageAllowedCache = [];
50 
54  public function ‪getWorkspaceId(): int
55  {
56  return $this->‪getBackendUser()->workspace;
57  }
58 
65  array $workspaceItems,
66  array $byTableName = ['tt_content', 'pages']
67  ): array {
68  $currentStage = [];
69  $previousStage = [];
70  $usedStages = [];
71  $found = false;
72  $availableStagesForWS = array_reverse($this->‪getAllStagesOfWorkspace());
73  $availableStagesForWSUser = $this->‪getStagesForWSUser();
74  $byTableName = array_flip($byTableName);
75  foreach ($workspaceItems as $tableName => $items) {
76  if (!array_key_exists($tableName, $byTableName)) {
77  continue;
78  }
79  foreach ($items as $item) {
80  $usedStages[$item['t3ver_stage'] ?? 0] = true;
81  }
82  }
83  foreach ($availableStagesForWS as $stage) {
84  if (isset($usedStages[$stage['uid']])) {
85  $currentStage = $stage;
86  $previousStage = $this->‪getPrevStage($stage['uid']);
87  break;
88  }
89  }
90  foreach ($availableStagesForWSUser as $userWS) {
91  if ($previousStage && $previousStage['uid'] == $userWS['uid']) {
92  $found = true;
93  break;
94  }
95  }
96  if ($found === false || !$this->‪isStageAllowedForUser($currentStage['uid'])) {
97  $previousStage = [];
98  }
99  return [
100  $currentStage,
101  $previousStage,
102  ];
103  }
104 
111  array $workspaceItems,
112  array $byTableName = ['tt_content', 'pages']
113  ): array {
114  $currentStage = [];
115  $usedStages = [];
116  $nextStage = [];
117  $availableStagesForWS = $this->‪getAllStagesOfWorkspace();
118  $availableStagesForWSUser = $this->‪getStagesForWSUser();
119  $byTableName = array_flip($byTableName);
120  $found = false;
121  foreach ($workspaceItems as $tableName => $items) {
122  if (!array_key_exists($tableName, $byTableName)) {
123  continue;
124  }
125  foreach ($items as $item) {
126  $usedStages[$item['t3ver_stage'] ?? 0] = true;
127  }
128  }
129  foreach ($availableStagesForWS as $stage) {
130  if (isset($usedStages[$stage['uid']])) {
131  $currentStage = $stage;
132  $nextStage = $this->‪getNextStage($stage['uid']);
133  break;
134  }
135  }
136  foreach ($availableStagesForWSUser as $userWS) {
137  if ($nextStage && $nextStage['uid'] == $userWS['uid']) {
138  $found = true;
139  break;
140  }
141  }
142  if ($found === false || !$this->‪isStageAllowedForUser($currentStage['uid'])) {
143  $nextStage = [];
144  }
145  return [
146  $currentStage,
147  $nextStage,
148  ];
149  }
150 
156  public function ‪getAllStagesOfWorkspace(): array
157  {
158  if (isset($this->workspaceStageCache[$this->‪getWorkspaceId()])) {
159  $stages = $this->workspaceStageCache[$this->‪getWorkspaceId()];
160  } elseif ($this->‪getWorkspaceId() === 0) {
161  $stages = [];
162  } else {
163  $stages = $this->‪prepareStagesArray($this->‪getWorkspaceRecord()->getStages());
164  $this->workspaceStageCache[$this->‪getWorkspaceId()] = $stages;
165  }
166  return $stages;
167  }
168 
174  public function ‪getStagesForWSUser(): array
175  {
176  if ($this->‪getBackendUser()->isAdmin()) {
177  return $this->‪getAllStagesOfWorkspace();
178  }
179  // The LIVE workspace has no stages
180  if ($this->‪getWorkspaceId() === 0) {
181  return [];
182  }
183 
185  $allowedStages = [];
186  $stageRecords = $this->‪getWorkspaceRecord()->getStages();
187 
188  // Only use stages that are allowed for current backend user
189  foreach ($stageRecords as $stageRecord) {
190  if ($stageRecord->isAllowed()) {
191  $allowedStages[$stageRecord->getUid()] = $stageRecord;
192  }
193  }
194 
195  // Add previous and next stages (even if they are not allowed!)
196  foreach ($allowedStages as $allowedStage) {
197  $previousStage = $allowedStage->getPrevious();
198  $nextStage = $allowedStage->getNext();
199  if ($previousStage !== null && !isset($allowedStages[$previousStage->getUid()])) {
200  $allowedStages[$previousStage->getUid()] = $previousStage;
201  }
202  if ($nextStage !== null && !isset($allowedStages[$nextStage->getUid()])) {
203  $allowedStages[$nextStage->getUid()] = $nextStage;
204  }
205  }
206 
207  uasort($allowedStages, static function (‪StageRecord $first, ‪StageRecord $second) {
208  return $first->‪determineOrder($second);
209  });
210  return $this->‪prepareStagesArray($allowedStages);
211  }
212 
218  protected function ‪prepareStagesArray(array $stageRecords): array
219  {
220  $stagesArray = [];
221  foreach ($stageRecords as $stageRecord) {
222  $stage = [
223  'uid' => $stageRecord->getUid(),
224  'label' => $stageRecord->getTitle(),
225  ];
226  if (!$stageRecord->isExecuteStage()) {
227  $stage['title'] = $this->‪getLanguageService()->sL($this->pathToLocallang . ':actionSendToStage') . ' "' . $stageRecord->getTitle() . '"';
228  } else {
229  $stage['title'] = $this->‪getLanguageService()->sL($this->pathToLocallang . ':publish_execute_action_option');
230  }
231  $stagesArray[] = $stage;
232  }
233  return $stagesArray;
234  }
235 
239  public function ‪getStageTitle(int $stageId): string
240  {
241  switch ($stageId) {
243  $stageTitle = $this->‪getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang_mod.xlf:stage_publish');
244  break;
246  $stageTitle = $this->‪getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang_mod.xlf:stage_ready_to_publish');
247  break;
249  $stageTitle = $this->‪getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang_mod.xlf:stage_editing');
250  break;
251  default:
252  $stageTitle = $this->‪getPropertyOfCurrentWorkspaceStage($stageId, 'title');
253  if ($stageTitle === null) {
254  $stageTitle = $this->‪getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:error.getStageTitle.stageNotFound');
255  }
256  }
257  return $stageTitle;
258  }
259 
266  public function ‪getNextStage(int $stageId): array
267  {
268  $nextStage = false;
269  $workspaceStageRecs = $this->‪getAllStagesOfWorkspace();
270  if ($workspaceStageRecs !== []) {
271  reset($workspaceStageRecs);
272  while (key($workspaceStageRecs) !== null) {
273  $workspaceStageRec = current($workspaceStageRecs);
274  if ($workspaceStageRec['uid'] == $stageId) {
275  $nextStage = next($workspaceStageRecs);
276  break;
277  }
278  next($workspaceStageRecs);
279  }
280  }
281  if ($nextStage === false) {
282  $nextStage = [
283  [
284  'uid' => ‪self::STAGE_EDIT_ID,
285  'title' => $this->‪getLanguageService()->sL($this->pathToLocallang . ':actionSendToStage') . ' "'
286  . $this->‪getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang_mod.xlf:stage_editing') . '"',
287  ],
288  ];
289  }
290  return $nextStage;
291  }
292 
300  protected function ‪getNextStages(array &$nextStageArray, int $stageId): array
301  {
302  // Current stage is "Ready to publish" - there is no next stage
303  if ($stageId == self::STAGE_PUBLISH_ID) {
304  return $nextStageArray;
305  }
306  $nextStageRecord = $this->‪getNextStage($stageId);
307  if ($nextStageRecord === []) {
308  // There is no next stage
309  return $nextStageArray;
310  }
311  // Check if the user has the permission to for the current stage
312  // If this next stage record is the first next stage after the current the user
313  // has always the needed permission
314  if ($this->‪isStageAllowedForUser($stageId)) {
315  $nextStageArray[] = $nextStageRecord;
316  return $this->‪getNextStages($nextStageArray, (int)$nextStageRecord['uid']);
317  }
318  // He hasn't - return given next stage array
319  return $nextStageArray;
320  }
321 
328  public function ‪getPrevStage(int $stageId): false|array
329  {
330  $prevStage = false;
331  $workspaceStageRecs = $this->‪getAllStagesOfWorkspace();
332  if ($workspaceStageRecs !== []) {
333  end($workspaceStageRecs);
334  while (key($workspaceStageRecs) !== null) {
335  $workspaceStageRec = current($workspaceStageRecs);
336  if ($workspaceStageRec['uid'] == $stageId) {
337  $prevStage = prev($workspaceStageRecs);
338  break;
339  }
340  prev($workspaceStageRecs);
341  }
342  }
343 
344  return $prevStage;
345  }
346 
354  protected function ‪getPrevStages(array &$prevStageArray, int $stageId): array
355  {
356  // Current stage is "Editing" - there is no prev stage
357  if ($stageId === self::STAGE_EDIT_ID) {
358  return $prevStageArray;
359  }
360  $prevStageRecord = $this->‪getPrevStage($stageId);
361  if (!empty($prevStageRecord) && is_array($prevStageRecord)) {
362  // Check if the user has the permission to switch to that stage
363  // If this prev stage record is the first previous stage before the current
364  // the user has always the needed permission
365  if ($this->‪isStageAllowedForUser($stageId)) {
366  $prevStageArray[] = $prevStageRecord;
367  $prevStageArray = $this->‪getPrevStages($prevStageArray, $prevStageRecord['uid']);
368  }
369  }
370  return $prevStageArray;
371  }
372 
380  public function ‪getResponsibleBeUser(‪StageRecord|int $stageRecord, bool $selectDefaultUserField = false): array
381  {
382  if (!$stageRecord instanceof ‪StageRecord) {
383  $stageRecord = $this->‪getWorkspaceRecord()->getStage($stageRecord);
384  }
385 
386  if (!$selectDefaultUserField) {
387  $backendUserIds = $stageRecord->getAllRecipients();
388  } else {
389  $backendUserIds = $stageRecord->getDefaultRecipients();
390  }
391 
392  $userRecords = $this->‪getBackendUsers($backendUserIds);
393  $recipientArray = [];
394  foreach ($userRecords as $userUid => $userRecord) {
395  $recipientArray[$userUid] = $userRecord;
396  }
397  return $recipientArray;
398  }
399 
404  public function ‪resolveBackendUserIds(string $backendUserGroupList): array
405  {
406  $elements = ‪GeneralUtility::trimExplode(',', $backendUserGroupList, true);
407  $backendUserIds = [];
408  $backendGroupIds = [];
409 
410  foreach ($elements as $element) {
411  if (str_starts_with($element, 'be_users_')) {
412  // Current value is a uid of a be_user record
413  $backendUserIds[] = str_replace('be_users_', '', $element);
414  } elseif (str_starts_with($element, 'be_groups_')) {
415  $backendGroupIds[] = (int)str_replace('be_groups_', '', $element);
416  } elseif ((int)$element) {
417  $backendUserIds[] = (int)$element;
418  }
419  }
420 
421  if (!empty($backendGroupIds)) {
422  $groupResolver = GeneralUtility::makeInstance(GroupResolver::class);
423  $backendUsersInGroups = $groupResolver->findAllUsersInGroups($backendGroupIds, 'be_groups', 'be_users');
424  foreach ($backendUsersInGroups as $backendUsers) {
425  $backendUserIds[] = (int)$backendUsers['uid'];
426  }
427  }
428 
429  return array_unique($backendUserIds);
430  }
431 
435  public function ‪getBackendUsers(array $backendUserIds): array
436  {
437  if ($backendUserIds === []) {
438  return [];
439  }
440  $backendUserList = implode(',', ‪GeneralUtility::intExplode(',', implode(',', $backendUserIds)));
441  return BackendUtility::getUserNames(
442  'username, uid, email, realName, lang, uc',
443  'AND uid IN (' . $backendUserList . ')' . BackendUtility::BEenableFields('be_users')
444  );
445  }
446 
447  public function ‪getPreselectedRecipients(‪StageRecord $stageRecord): array
448  {
449  if ($stageRecord->‪areEditorsPreselected()) {
450  return array_merge(
451  $stageRecord->‪getPreselectedRecipients(),
452  $this->getRecordService()->getCreateUserIds()
453  );
454  }
455  return $stageRecord->‪getPreselectedRecipients();
456  }
457 
459  {
461  }
462 
466  public function ‪getPropertyOfCurrentWorkspaceStage(int $stageId, string $property): ?string
467  {
468  $result = null;
469  $workspaceStage = BackendUtility::getRecord(self::TABLE_STAGE, $stageId);
470  if (is_array($workspaceStage) && isset($workspaceStage[$property])) {
471  $result = $workspaceStage[$property];
472  }
473  return $result;
474  }
475 
482  public function ‪getPositionOfCurrentStage(int $stageId): array
483  {
484  $stagesOfWS = $this->‪getAllStagesOfWorkspace();
485  $countOfStages = count($stagesOfWS);
486  switch ($stageId) {
488  $position = $countOfStages;
489  break;
491  $position = 1;
492  break;
493  default:
494  $position = 1;
495  foreach ($stagesOfWS as $stageInfoArray) {
496  $position++;
497  if ($stageId === (int)$stageInfoArray['uid']) {
498  break;
499  }
500  }
501  }
502  return ['position' => $position, 'count' => $countOfStages];
503  }
504 
508  public function ‪isPrevStageAllowedForUser(int $stageId): bool
509  {
510  $isAllowed = false;
511  try {
512  $prevStage = $this->‪getPrevStage($stageId);
513  // if there's no prev-stage the stageIds match,
514  // otherwise we've to check if the user is permitted to use the stage
515  if (!empty($prevStage) && $prevStage['uid'] != $stageId) {
516  // if the current stage is allowed for the user, the user is also allowed to send to prev
517  $isAllowed = $this->‪isStageAllowedForUser($stageId);
518  }
519  } catch (\Exception $e) {
520  }
521  return $isAllowed;
522  }
523 
527  public function ‪isNextStageAllowedForUser(int $stageId): bool
528  {
529  $isAllowed = false;
530  try {
531  $nextStage = $this->‪getNextStage($stageId);
532  // if there's no next-stage the stageIds match,
533  // otherwise we've to check if the user is permitted to use the stage
534  if (!empty($nextStage) && $nextStage['uid'] != $stageId) {
535  // if the current stage is allowed for the user, the user is also allowed to send to next
536  $isAllowed = $this->‪isStageAllowedForUser($stageId);
537  }
538  } catch (\Exception $e) {
539  }
540  return $isAllowed;
541  }
542 
543  protected function ‪isStageAllowedForUser(int $stageId): bool
544  {
545  $cacheKey = $this->‪getWorkspaceId() . '_' . $stageId;
546  if (isset($this->workspaceStageAllowedCache[$cacheKey])) {
547  return $this->workspaceStageAllowedCache[$cacheKey];
548  }
549  $isAllowed = $this->‪getBackendUser()->workspaceCheckStageForCurrent($stageId);
550  $this->workspaceStageAllowedCache[$cacheKey] = $isAllowed;
551  return $isAllowed;
552  }
553 
557  public function ‪isValid(int $stageId): bool
558  {
559  $isValid = false;
560  $stages = $this->‪getAllStagesOfWorkspace();
561  foreach ($stages as $stage) {
562  if ($stage['uid'] == $stageId) {
563  $isValid = true;
564  break;
565  }
566  }
567  return $isValid;
568  }
569 
571  {
572  if (!isset($this->recordService)) {
573  $this->recordService = GeneralUtility::makeInstance(RecordService::class);
574  }
576  }
577 
579  {
580  return ‪$GLOBALS['BE_USER'];
581  }
582 
584  {
585  return ‪$GLOBALS['LANG'] ?? null;
586  }
587 }
‪TYPO3\CMS\Workspaces\Service\StagesService\getPositionOfCurrentStage
‪array getPositionOfCurrentStage(int $stageId)
Definition: StagesService.php:482
‪TYPO3\CMS\Workspaces\Service\StagesService\getWorkspaceRecord
‪getWorkspaceRecord()
Definition: StagesService.php:458
‪TYPO3\CMS\Workspaces\Service\StagesService\$workspaceStageAllowedCache
‪array $workspaceStageAllowedCache
Definition: StagesService.php:49
‪TYPO3\CMS\Workspaces\Service
‪TYPO3\CMS\Workspaces\Service\StagesService\isStageAllowedForUser
‪isStageAllowedForUser(int $stageId)
Definition: StagesService.php:543
‪TYPO3\CMS\Workspaces\Domain\Record\StageRecord\determineOrder
‪determineOrder(StageRecord $stageRecord)
Definition: StageRecord.php:73
‪TYPO3\CMS\Workspaces\Service\StagesService\getPropertyOfCurrentWorkspaceStage
‪getPropertyOfCurrentWorkspaceStage(int $stageId, string $property)
Definition: StagesService.php:466
‪TYPO3\CMS\Workspaces\Service\StagesService\getRecordService
‪getRecordService()
Definition: StagesService.php:570
‪TYPO3\CMS\Workspaces\Service\StagesService\getPrevStage
‪false array getPrevStage(int $stageId)
Definition: StagesService.php:328
‪TYPO3\CMS\Workspaces\Domain\Record\WorkspaceRecord
Definition: WorkspaceRecord.php:31
‪TYPO3\CMS\Workspaces\Service\StagesService\STAGE_PUBLISH_EXECUTE_ID
‪const STAGE_PUBLISH_EXECUTE_ID
Definition: StagesService.php:36
‪TYPO3\CMS\Workspaces\Domain\Record\StageRecord\getPreselectedRecipients
‪int[] getPreselectedRecipients()
Definition: StageRecord.php:243
‪TYPO3\CMS\Workspaces\Service\StagesService\STAGE_PUBLISH_ID
‪const STAGE_PUBLISH_ID
Definition: StagesService.php:38
‪TYPO3\CMS\Workspaces\Service\StagesService\isNextStageAllowedForUser
‪isNextStageAllowedForUser(int $stageId)
Definition: StagesService.php:527
‪TYPO3\CMS\Workspaces\Service\StagesService\getAllStagesOfWorkspace
‪array getAllStagesOfWorkspace()
Definition: StagesService.php:156
‪TYPO3\CMS\Workspaces\Service\StagesService\getBackendUser
‪getBackendUser()
Definition: StagesService.php:578
‪TYPO3\CMS\Workspaces\Service\StagesService\getStagesForWSUser
‪array getStagesForWSUser()
Definition: StagesService.php:174
‪TYPO3\CMS\Workspaces\Domain\Record\WorkspaceRecord\get
‪static get(int $uid, array $record=null)
Definition: WorkspaceRecord.php:61
‪TYPO3\CMS\Workspaces\Domain\Record\StageRecord
Definition: StageRecord.php:28
‪TYPO3\CMS\Workspaces\Service\StagesService\resolveBackendUserIds
‪resolveBackendUserIds(string $backendUserGroupList)
Definition: StagesService.php:404
‪TYPO3\CMS\Workspaces\Service\StagesService\isValid
‪isValid(int $stageId)
Definition: StagesService.php:557
‪TYPO3\CMS\Workspaces\Service\StagesService\getPreviousStageForElementCollection
‪array getPreviousStageForElementCollection(array $workspaceItems, array $byTableName=['tt_content', 'pages'])
Definition: StagesService.php:64
‪TYPO3\CMS\Workspaces\Service\StagesService\getPreselectedRecipients
‪getPreselectedRecipients(StageRecord $stageRecord)
Definition: StagesService.php:447
‪TYPO3\CMS\Workspaces\Service\StagesService\isPrevStageAllowedForUser
‪isPrevStageAllowedForUser(int $stageId)
Definition: StagesService.php:508
‪TYPO3\CMS\Workspaces\Service\StagesService\$recordService
‪RecordService $recordService
Definition: StagesService.php:43
‪TYPO3\CMS\Workspaces\Service\StagesService\getPrevStages
‪array getPrevStages(array &$prevStageArray, int $stageId)
Definition: StagesService.php:354
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Workspaces\Service\StagesService\$pathToLocallang
‪string $pathToLocallang
Definition: StagesService.php:41
‪TYPO3\CMS\Workspaces\Service\StagesService\getLanguageService
‪getLanguageService()
Definition: StagesService.php:583
‪TYPO3\CMS\Workspaces\Domain\Record\StageRecord\areEditorsPreselected
‪areEditorsPreselected()
Definition: StageRecord.php:171
‪TYPO3\CMS\Core\Authentication\GroupResolver
Definition: GroupResolver.php:36
‪TYPO3\CMS\Workspaces\Service\StagesService\prepareStagesArray
‪prepareStagesArray(array $stageRecords)
Definition: StagesService.php:218
‪TYPO3\CMS\Workspaces\Service\StagesService\STAGE_EDIT_ID
‪const STAGE_EDIT_ID
Definition: StagesService.php:39
‪TYPO3\CMS\Workspaces\Service\StagesService
Definition: StagesService.php:33
‪TYPO3\CMS\Workspaces\Service\StagesService\getNextStage
‪array getNextStage(int $stageId)
Definition: StagesService.php:266
‪TYPO3\CMS\Workspaces\Service\StagesService\$workspaceStageCache
‪array $workspaceStageCache
Definition: StagesService.php:48
‪TYPO3\CMS\Workspaces\Service\StagesService\getNextStages
‪array getNextStages(array &$nextStageArray, int $stageId)
Definition: StagesService.php:300
‪TYPO3\CMS\Workspaces\Service\StagesService\getResponsibleBeUser
‪array getResponsibleBeUser(StageRecord|int $stageRecord, bool $selectDefaultUserField=false)
Definition: StagesService.php:380
‪TYPO3\CMS\Core\SingletonInterface
Definition: SingletonInterface.php:22
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Workspaces\Service\StagesService\getWorkspaceId
‪getWorkspaceId()
Definition: StagesService.php:54
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Workspaces\Service\StagesService\getStageTitle
‪getStageTitle(int $stageId)
Definition: StagesService.php:239
‪TYPO3\CMS\Workspaces\Service\StagesService\TABLE_STAGE
‪const TABLE_STAGE
Definition: StagesService.php:34
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static list< int > intExplode(string $delimiter, string $string, bool $removeEmptyValues=false)
Definition: GeneralUtility.php:756
‪TYPO3\CMS\Workspaces\Service\RecordService
Definition: RecordService.php:29
‪TYPO3\CMS\Workspaces\Service\StagesService\getNextStageForElementCollection
‪array getNextStageForElementCollection(array $workspaceItems, array $byTableName=['tt_content', 'pages'])
Definition: StagesService.php:110
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822
‪TYPO3\CMS\Workspaces\Service\StagesService\getBackendUsers
‪getBackendUsers(array $backendUserIds)
Definition: StagesService.php:435