[BUGFIX] Fix several typos in php comments
[Packages/TYPO3.CMS.git] / typo3 / sysext / workspaces / Classes / Controller / Remote / ActionHandler.php
1 <?php
2 namespace TYPO3\CMS\Workspaces\Controller\Remote;
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\Authentication\BackendUserAuthentication;
19 use TYPO3\CMS\Core\DataHandling\DataHandler;
20 use TYPO3\CMS\Core\Exception;
21 use TYPO3\CMS\Core\Localization\LanguageService;
22 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24 use TYPO3\CMS\Core\Utility\MathUtility;
25 use TYPO3\CMS\Fluid\View\StandaloneView;
26 use TYPO3\CMS\Workspaces\Domain\Record\StageRecord;
27 use TYPO3\CMS\Workspaces\Domain\Record\WorkspaceRecord;
28 use TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder;
29 use TYPO3\CMS\Workspaces\Service\StagesService;
30 use TYPO3\CMS\Workspaces\Service\WorkspaceService;
31
32 /**
33 * @internal This is a specific Backend Controller implementation and is not considered part of the Public TYPO3 API.
34 */
35 class ActionHandler
36 {
37 /**
38 * @var StagesService
39 */
40 protected $stageService;
41
42 /**
43 * @var WorkspaceService
44 */
45 protected $workspaceService;
46
47 /**
48 * Creates this object.
49 */
50 public function __construct()
51 {
52 $this->stageService = GeneralUtility::makeInstance(StagesService::class);
53 $this->workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
54 }
55
56 /**
57 * Generates a workspace preview link.
58 *
59 * @param int $uid The ID of the record to be linked
60 * @return string the full domain including the protocol http:// or https://, but without the trailing '/'
61 */
62 public function generateWorkspacePreviewLink($uid)
63 {
64 return GeneralUtility::makeInstance(PreviewUriBuilder::class)->buildUriForPage((int)$uid, 0);
65 }
66
67 /**
68 * Generates workspace preview links for all available languages of a page.
69 *
70 * @param int $uid
71 * @return array
72 */
73 public function generateWorkspacePreviewLinksForAllLanguages($uid)
74 {
75 return GeneralUtility::makeInstance(PreviewUriBuilder::class)->buildUrisForAllLanguagesOfPage((int)$uid);
76 }
77
78 /**
79 * Swaps a single record.
80 *
81 * @param string $table
82 * @param int $t3ver_oid
83 * @param int $orig_uid
84 * @todo What about reporting errors back to the interface? /olly/
85 */
86 public function swapSingleRecord($table, $t3ver_oid, $orig_uid)
87 {
88 $versionRecord = BackendUtility::getRecord($table, $orig_uid);
89 $currentWorkspace = $this->setTemporaryWorkspace($versionRecord['t3ver_wsid']);
90
91 $cmd[$table][$t3ver_oid]['version'] = [
92 'action' => 'swap',
93 'swapWith' => $orig_uid,
94 'swapIntoWS' => 1
95 ];
96 $this->processTcaCmd($cmd);
97
98 $this->setTemporaryWorkspace($currentWorkspace);
99 }
100
101 /**
102 * Deletes a single record.
103 *
104 * @param string $table
105 * @param int $uid
106 * @todo What about reporting errors back to the interface? /olly/
107 */
108 public function deleteSingleRecord($table, $uid)
109 {
110 $versionRecord = BackendUtility::getRecord($table, $uid);
111 $currentWorkspace = $this->setTemporaryWorkspace($versionRecord['t3ver_wsid']);
112
113 $cmd[$table][$uid]['version'] = [
114 'action' => 'clearWSID'
115 ];
116 $this->processTcaCmd($cmd);
117
118 $this->setTemporaryWorkspace($currentWorkspace);
119 }
120
121 /**
122 * Generates a view link for a page.
123 *
124 * @param string $table
125 * @param string $uid
126 * @return string
127 */
128 public function viewSingleRecord($table, $uid)
129 {
130 return GeneralUtility::makeInstance(PreviewUriBuilder::class)->buildUriForElement($table, $uid);
131 }
132
133 /**
134 * Executes an action (publish, discard, swap) to a selection set.
135 *
136 * @param \stdClass $parameter
137 * @return array
138 */
139 public function executeSelectionAction($parameter)
140 {
141 $result = [];
142
143 if (empty($parameter->action) || empty($parameter->selection)) {
144 $result['error'] = 'No action or record selection given';
145 return $result;
146 }
147
148 $commands = [];
149 $swapIntoWorkspace = ($parameter->action === 'swap');
150 if ($parameter->action === 'publish' || $swapIntoWorkspace) {
151 $commands = $this->getPublishSwapCommands($parameter->selection, $swapIntoWorkspace);
152 } elseif ($parameter->action === 'discard') {
153 $commands = $this->getFlushCommands($parameter->selection);
154 }
155
156 $result = $this->processTcaCmd($commands);
157 $result['total'] = count($commands);
158 return $result;
159 }
160
161 /**
162 * Get publish swap commands
163 *
164 * @param array|\stdClass[] $selection
165 * @param bool $swapIntoWorkspace
166 * @return array
167 */
168 protected function getPublishSwapCommands(array $selection, $swapIntoWorkspace)
169 {
170 $commands = [];
171 foreach ($selection as $record) {
172 $commands[$record->table][$record->liveId]['version'] = [
173 'action' => 'swap',
174 'swapWith' => $record->versionId,
175 'swapIntoWS' => (bool)$swapIntoWorkspace,
176 ];
177 }
178 return $commands;
179 }
180
181 /**
182 * Get flush commands
183 *
184 * @param array|\stdClass[] $selection
185 * @return array
186 */
187 protected function getFlushCommands(array $selection)
188 {
189 $commands = [];
190 foreach ($selection as $record) {
191 $commands[$record->table][$record->versionId]['version'] = [
192 'action' => 'clearWSID',
193 ];
194 }
195 return $commands;
196 }
197
198 /**
199 * Saves the selected columns to be shown to the preferences of the current backend user.
200 *
201 * @param \stdClass $model
202 */
203 public function saveColumnModel($model)
204 {
205 $data = [];
206 foreach ($model as $column) {
207 $data[$column->column] = [
208 'position' => $column->position,
209 'hidden' => $column->hidden
210 ];
211 }
212 $this->getBackendUser()->uc['moduleData']['Workspaces'][$this->getBackendUser()->workspace]['columns'] = $data;
213 $this->getBackendUser()->writeUC();
214 }
215
216 public function loadColumnModel()
217 {
218 if (is_array($this->getBackendUser()->uc['moduleData']['Workspaces'][$this->getBackendUser()->workspace]['columns'])) {
219 return $this->getBackendUser()->uc['moduleData']['Workspaces'][$this->getBackendUser()->workspace]['columns'];
220 }
221 return [];
222 }
223
224 /**
225 * Saves the selected language.
226 *
227 * @param int|string $language
228 */
229 public function saveLanguageSelection($language)
230 {
231 if (MathUtility::canBeInterpretedAsInteger($language) === false && $language !== 'all') {
232 $language = 'all';
233 }
234 $this->getBackendUser()->uc['moduleData']['Workspaces'][$this->getBackendUser()->workspace]['language'] = $language;
235 $this->getBackendUser()->writeUC();
236 }
237
238 /**
239 * Gets the dialog window to be displayed before a record can be sent to the next stage.
240 *
241 * @param int $uid
242 * @param string $table
243 * @param int $t3ver_oid
244 * @return array
245 */
246 public function sendToNextStageWindow($uid, $table, $t3ver_oid)
247 {
248 $elementRecord = BackendUtility::getRecord($table, $uid);
249 $currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
250
251 if (is_array($elementRecord)) {
252 $workspaceRecord = WorkspaceRecord::get($elementRecord['t3ver_wsid']);
253 $nextStageRecord = $workspaceRecord->getNextStage($elementRecord['t3ver_stage']);
254 if ($nextStageRecord !== null) {
255 $this->stageService->getRecordService()->add($table, $uid);
256 $result = $this->getSentToStageWindow($nextStageRecord);
257 $result['affects'] = [
258 'table' => $table,
259 'nextStage' => $nextStageRecord->getUid(),
260 't3ver_oid' => $t3ver_oid,
261 'uid' => $uid
262 ];
263 } else {
264 $result = $this->getErrorResponse('error.stageId.invalid', 1291111644);
265 }
266 } else {
267 $result = $this->getErrorResponse('error.sendToNextStage.noRecordFound', 1287264776);
268 }
269
270 $this->setTemporaryWorkspace($currentWorkspace);
271 return $result;
272 }
273
274 /**
275 * Gets the dialog window to be displayed before a record can be sent to the previous stage.
276 *
277 * @param int $uid
278 * @param string $table
279 * @return array
280 */
281 public function sendToPrevStageWindow($uid, $table)
282 {
283 $elementRecord = BackendUtility::getRecord($table, $uid);
284 $currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
285
286 if (is_array($elementRecord)) {
287 $workspaceRecord = WorkspaceRecord::get($elementRecord['t3ver_wsid']);
288 $stageRecord = $workspaceRecord->getStage($elementRecord['t3ver_stage']);
289
290 if ($stageRecord !== null) {
291 if (!$stageRecord->isEditStage()) {
292 $this->stageService->getRecordService()->add($table, $uid);
293 $previousStageRecord = $stageRecord->getPrevious();
294 $result = $this->getSentToStageWindow($previousStageRecord);
295 $result['affects'] = [
296 'table' => $table,
297 'uid' => $uid,
298 'nextStage' => $previousStageRecord->getUid()
299 ];
300 } else {
301 // element is already in edit stage, there is no prev stage - return an error message
302 $result = $this->getErrorResponse('error.sendToPrevStage.noPreviousStage', 1287264746);
303 }
304 } else {
305 $result = $this->getErrorResponse('error.stageId.invalid', 1291111644);
306 }
307 } else {
308 $result = $this->getErrorResponse('error.sendToNextStage.noRecordFound', 1287264765);
309 }
310
311 $this->setTemporaryWorkspace($currentWorkspace);
312 return $result;
313 }
314
315 /**
316 * Gets the dialog window to be displayed before a record can be sent to a specific stage.
317 *
318 * @param int $nextStageId
319 * @param array|\stdClass[] $elements
320 * @return array
321 */
322 public function sendToSpecificStageWindow($nextStageId, array $elements)
323 {
324 foreach ($elements as $element) {
325 $this->stageService->getRecordService()->add(
326 $element->table,
327 $element->uid
328 );
329 }
330
331 $result = $this->getSentToStageWindow($nextStageId);
332 $result['affects'] = [
333 'nextStage' => $nextStageId
334 ];
335 return $result;
336 }
337
338 /**
339 * Gets a merged variant of recipient defined by uid and custom ones.
340 *
341 * @param array $uidOfRecipients list of recipients
342 * @param string $additionalRecipients given user string of additional recipients
343 * @param int $stageId stage id
344 * @return array
345 * @throws \InvalidArgumentException
346 */
347 public function getRecipientList(array $uidOfRecipients, $additionalRecipients, $stageId)
348 {
349 $stageRecord = WorkspaceRecord::get($this->getCurrentWorkspace())->getStage($stageId);
350
351 if ($stageRecord === null) {
352 throw new \InvalidArgumentException(
353 $this->getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:error.stageId.integer'),
354 1476044776
355 );
356 }
357
358 $recipients = [];
359 $finalRecipients = [];
360 $backendUserIds = $stageRecord->getAllRecipients();
361 foreach ($uidOfRecipients as $userUid) {
362 // Ensure that only configured backend users are considered
363 if (!in_array($userUid, $backendUserIds)) {
364 continue;
365 }
366 $beUserRecord = BackendUtility::getRecord('be_users', (int)$userUid);
367 if (is_array($beUserRecord) && $beUserRecord['email'] !== '') {
368 $uc = $beUserRecord['uc'] ? unserialize($beUserRecord['uc']) : [];
369 $recipients[$beUserRecord['email']] = [
370 'email' => $beUserRecord['email'],
371 'lang' => $uc['lang'] ?? $beUserRecord['lang']
372 ];
373 }
374 }
375
376 if ($stageRecord->hasPreselection() && !$stageRecord->isPreselectionChangeable()) {
377 $preselectedBackendUsers = $this->stageService->getBackendUsers(
378 implode(',', $this->stageService->getPreselectedRecipients($stageRecord))
379 );
380
381 foreach ($preselectedBackendUsers as $preselectedBackendUser) {
382 if (empty($preselectedBackendUser['email']) || !GeneralUtility::validEmail($preselectedBackendUser['email'])) {
383 continue;
384 }
385 if (!isset($recipients[$preselectedBackendUser['email']])) {
386 $uc = (!empty($preselectedBackendUser['uc']) ? unserialize($preselectedBackendUser['uc']) : []);
387 $recipients[$preselectedBackendUser['email']] = [
388 'email' => $preselectedBackendUser['email'],
389 'lang' => $uc['lang'] ?? $preselectedBackendUser['lang']
390 ];
391 }
392 }
393 }
394
395 if ($additionalRecipients !== '') {
396 $emails = GeneralUtility::trimExplode(LF, $additionalRecipients, true);
397 $additionalRecipients = [];
398 foreach ($emails as $email) {
399 $additionalRecipients[$email] = ['email' => $email];
400 }
401 } else {
402 $additionalRecipients = [];
403 }
404 // We merge $recipients on top of $additionalRecipients because $recipients
405 // possibly is more complete with a user language. Furthermore, the list of
406 // recipients is automatically unique since we indexed $additionalRecipients
407 // and $recipients with the email address
408 $allRecipients = array_merge($additionalRecipients, $recipients);
409 foreach ($allRecipients as $email => $recipientInformation) {
410 if (GeneralUtility::validEmail($email)) {
411 $finalRecipients[] = $recipientInformation;
412 }
413 }
414 return $finalRecipients;
415 }
416
417 /**
418 * Discard all items from given page id.
419 *
420 * @param int $pageId
421 * @return array
422 */
423 public function discardStagesFromPage($pageId)
424 {
425 $cmdMapArray = [];
426 $workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
427 $this->stageService->getWorkspaceId(),
428 $filter = 1,
429 $stage = -99,
430 $pageId,
431 $recursionLevel = 0,
432 $selectionType = 'tables_modify'
433 );
434 foreach ($workspaceItemsArray as $tableName => $items) {
435 foreach ($items as $item) {
436 $cmdMapArray[$tableName][$item['uid']]['version']['action'] = 'clearWSID';
437 }
438 }
439 $this->processTcaCmd($cmdMapArray);
440 return [
441 'success' => true
442 ];
443 }
444
445 /**
446 * Push the given element collection to the next workspace stage.
447 *
448 * <code>
449 * $parameters->additional = your@mail.com
450 * $parameters->affects->__TABLENAME__
451 * $parameters->comments
452 * $parameters->recipients
453 * $parameters->stageId
454 * </code>
455 *
456 * @param \stdClass $parameters
457 * @return array
458 */
459 public function sentCollectionToStage(\stdClass $parameters)
460 {
461 $cmdMapArray = [];
462 $comment = $parameters->comments;
463 $stageId = $parameters->stageId;
464 if (MathUtility::canBeInterpretedAsInteger($stageId) === false) {
465 throw new \InvalidArgumentException('Missing "stageId" in $parameters array.', 1319488194);
466 }
467 if (!is_object($parameters->affects) || empty($parameters->affects)) {
468 throw new \InvalidArgumentException('Missing "affected items" in $parameters array.', 1319488195);
469 }
470 $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $stageId);
471 foreach ($parameters->affects as $tableName => $items) {
472 foreach ($items as $item) {
473 // Publishing uses live id in command map
474 if ($stageId == StagesService::STAGE_PUBLISH_EXECUTE_ID) {
475 $cmdMapArray[$tableName][$item->t3ver_oid]['version']['action'] = 'swap';
476 $cmdMapArray[$tableName][$item->t3ver_oid]['version']['swapWith'] = $item->uid;
477 $cmdMapArray[$tableName][$item->t3ver_oid]['version']['comment'] = $comment;
478 $cmdMapArray[$tableName][$item->t3ver_oid]['version']['notificationAlternativeRecipients'] = $recipients;
479 } else {
480 // Setting stage uses version id in command map
481 $cmdMapArray[$tableName][$item->uid]['version']['action'] = 'setStage';
482 $cmdMapArray[$tableName][$item->uid]['version']['stageId'] = $stageId;
483 $cmdMapArray[$tableName][$item->uid]['version']['comment'] = $comment;
484 $cmdMapArray[$tableName][$item->uid]['version']['notificationAlternativeRecipients'] = $recipients;
485 }
486 }
487 }
488 $this->processTcaCmd($cmdMapArray);
489 return [
490 'success' => true,
491 // force refresh after publishing changes
492 'refreshLivePanel' => $parameters->stageId == -20
493 ];
494 }
495
496 /**
497 * Process TCA command map array.
498 *
499 * @param array $cmdMapArray
500 * @return array
501 */
502 protected function processTcaCmd(array $cmdMapArray)
503 {
504 $result = [];
505
506 if (empty($cmdMapArray)) {
507 $result['error'] = 'No commands given to be processed';
508 return $result;
509 }
510
511 $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
512 $dataHandler->start([], $cmdMapArray);
513 $dataHandler->process_cmdmap();
514
515 if ($dataHandler->errorLog) {
516 $result['error'] = implode('<br/>', $dataHandler->errorLog);
517 }
518
519 return $result;
520 }
521
522 /**
523 * Gets an object with this structure:
524 *
525 * affects: object
526 * table
527 * t3ver_oid
528 * nextStage
529 * uid
530 * recipients: array with uids
531 * additional: string
532 * comments: string
533 *
534 * @param \stdClass $parameters
535 * @return array
536 */
537 public function sendToNextStageExecute(\stdClass $parameters)
538 {
539 $cmdArray = [];
540 $setStageId = $parameters->affects->nextStage;
541 $comments = $parameters->comments;
542 $table = $parameters->affects->table;
543 $uid = $parameters->affects->uid;
544 $t3ver_oid = $parameters->affects->t3ver_oid;
545
546 $elementRecord = BackendUtility::getRecord($table, $uid);
547 $currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
548
549 $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $setStageId);
550 if ($setStageId == StagesService::STAGE_PUBLISH_EXECUTE_ID) {
551 $cmdArray[$table][$t3ver_oid]['version']['action'] = 'swap';
552 $cmdArray[$table][$t3ver_oid]['version']['swapWith'] = $uid;
553 $cmdArray[$table][$t3ver_oid]['version']['comment'] = $comments;
554 $cmdArray[$table][$t3ver_oid]['version']['notificationAlternativeRecipients'] = $recipients;
555 } else {
556 $cmdArray[$table][$uid]['version']['action'] = 'setStage';
557 $cmdArray[$table][$uid]['version']['stageId'] = $setStageId;
558 $cmdArray[$table][$uid]['version']['comment'] = $comments;
559 $cmdArray[$table][$uid]['version']['notificationAlternativeRecipients'] = $recipients;
560 }
561 $this->processTcaCmd($cmdArray);
562 $result = [
563 'success' => true
564 ];
565
566 $this->setTemporaryWorkspace($currentWorkspace);
567 return $result;
568 }
569
570 /**
571 * Gets an object with this structure:
572 *
573 * affects: object
574 * table
575 * t3ver_oid
576 * nextStage
577 * recipients: array with uids
578 * additional: string
579 * comments: string
580 *
581 * @param \stdClass $parameters
582 * @return array
583 */
584 public function sendToPrevStageExecute(\stdClass $parameters)
585 {
586 $cmdArray = [];
587 $setStageId = $parameters->affects->nextStage;
588 $comments = $parameters->comments;
589 $table = $parameters->affects->table;
590 $uid = $parameters->affects->uid;
591
592 $elementRecord = BackendUtility::getRecord($table, $uid);
593 $currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
594
595 $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $setStageId);
596 $cmdArray[$table][$uid]['version']['action'] = 'setStage';
597 $cmdArray[$table][$uid]['version']['stageId'] = $setStageId;
598 $cmdArray[$table][$uid]['version']['comment'] = $comments;
599 $cmdArray[$table][$uid]['version']['notificationAlternativeRecipients'] = $recipients;
600 $this->processTcaCmd($cmdArray);
601 $result = [
602 'success' => true
603 ];
604
605 $this->setTemporaryWorkspace($currentWorkspace);
606 return $result;
607 }
608
609 /**
610 * Gets an object with this structure:
611 *
612 * affects: object
613 * elements: array
614 * 0: object
615 * table
616 * t3ver_oid
617 * uid
618 * 1: object
619 * table
620 * t3ver_oid
621 * uid
622 * nextStage
623 * recipients: array with uids
624 * additional: string
625 * comments: string
626 *
627 * @param \stdClass $parameters
628 * @return array
629 */
630 public function sendToSpecificStageExecute(\stdClass $parameters)
631 {
632 $cmdArray = [];
633 $setStageId = $parameters->affects->nextStage;
634 $comments = $parameters->comments;
635 $elements = $parameters->affects->elements;
636 $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $setStageId);
637 foreach ($elements as $element) {
638 // Avoid any action on records that have already been published to live
639 $elementRecord = BackendUtility::getRecord($element->table, $element->uid);
640 if ((int)$elementRecord['t3ver_wsid'] === 0) {
641 continue;
642 }
643
644 if ($setStageId == StagesService::STAGE_PUBLISH_EXECUTE_ID) {
645 $cmdArray[$element->table][$element->t3ver_oid]['version']['action'] = 'swap';
646 $cmdArray[$element->table][$element->t3ver_oid]['version']['swapWith'] = $element->uid;
647 $cmdArray[$element->table][$element->t3ver_oid]['version']['comment'] = $comments;
648 $cmdArray[$element->table][$element->t3ver_oid]['version']['notificationAlternativeRecipients'] = $recipients;
649 } else {
650 $cmdArray[$element->table][$element->uid]['version']['action'] = 'setStage';
651 $cmdArray[$element->table][$element->uid]['version']['stageId'] = $setStageId;
652 $cmdArray[$element->table][$element->uid]['version']['comment'] = $comments;
653 $cmdArray[$element->table][$element->uid]['version']['notificationAlternativeRecipients'] = $recipients;
654 }
655 }
656 $this->processTcaCmd($cmdArray);
657 $result = [
658 'success' => true
659 ];
660 return $result;
661 }
662
663 /**
664 * Gets the dialog window to be displayed before a record can be sent to a stage.
665 *
666 * @param StageRecord|int $nextStage
667 * @return array
668 */
669 protected function getSentToStageWindow($nextStage)
670 {
671 if (!$nextStage instanceof StageRecord) {
672 $nextStage = WorkspaceRecord::get($this->getCurrentWorkspace())->getStage($nextStage);
673 }
674
675 $result = [];
676 if ($nextStage->isDialogEnabled()) {
677 $result['sendMailTo'] = $this->getRecipientsOfStage($nextStage);
678 $result['additional'] = [
679 'type' => 'textarea',
680 'value' => ''
681 ];
682 }
683 $result['comments'] = [
684 'type' => 'textarea',
685 'value' => $nextStage->isInternal() ? '' : $nextStage->getDefaultComment()
686 ];
687
688 return $result;
689 }
690
691 /**
692 * Gets all assigned recipients of a particular stage.
693 *
694 * @param StageRecord|int $stageRecord
695 * @return array
696 */
697 protected function getRecipientsOfStage($stageRecord)
698 {
699 if (!$stageRecord instanceof StageRecord) {
700 $stageRecord = WorkspaceRecord::get($this->getCurrentWorkspace())->getStage($stageRecord);
701 }
702
703 $result = [];
704 $allRecipients = $this->stageService->getResponsibleBeUser($stageRecord);
705 $preselectedRecipients = $this->stageService->getPreselectedRecipients($stageRecord);
706 $isPreselectionChangeable = $stageRecord->isPreselectionChangeable();
707
708 foreach ($allRecipients as $backendUserId => $backendUser) {
709 if (empty($backendUser['email']) || !GeneralUtility::validEmail($backendUser['email'])) {
710 continue;
711 }
712
713 $name = (!empty($backendUser['realName']) ? $backendUser['realName'] : $backendUser['username']);
714 $checked = in_array($backendUserId, $preselectedRecipients);
715 $disabled = ($checked && !$isPreselectionChangeable);
716
717 $result[] = [
718 'label' => sprintf('%s (%s)', $name, $backendUser['email']),
719 'value' => $backendUserId,
720 'name' => 'recipients-' . $backendUserId,
721 'checked' => $checked,
722 'disabled' => $disabled
723 ];
724 }
725
726 return $result;
727 }
728
729 /**
730 * Gets the default comment of a particular stage.
731 *
732 * @param int $stage
733 * @return string
734 */
735 protected function getDefaultCommentOfStage($stage)
736 {
737 $result = $this->stageService->getPropertyOfCurrentWorkspaceStage($stage, 'default_mailcomment');
738 return $result;
739 }
740
741 /**
742 * Send all available workspace records to the previous stage.
743 *
744 * @param int $id Current page id to process items to previous stage.
745 * @return array
746 */
747 public function sendPageToPreviousStage($id)
748 {
749 $workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
750 $this->stageService->getWorkspaceId(),
751 $filter = 1,
752 $stage = -99,
753 $id,
754 $recursionLevel = 0,
755 $selectionType = 'tables_modify'
756 );
757 list($currentStage, $previousStage) = $this->stageService->getPreviousStageForElementCollection($workspaceItemsArray);
758 // get only the relevant items for processing
759 $workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
760 $this->stageService->getWorkspaceId(),
761 $filter = 1,
762 $currentStage['uid'],
763 $id,
764 $recursionLevel = 0,
765 $selectionType = 'tables_modify'
766 );
767 $stageFormFields = $this->getSentToStageWindow($previousStage['uid']);
768 $result = array_merge($stageFormFields, [
769 'title' => 'Status message: Page send to next stage - ID: ' . $id . ' - Next stage title: ' . $previousStage['title'],
770 'items' => $this->getSentToStageWindow($previousStage['uid']),
771 'affects' => $workspaceItemsArray,
772 'stageId' => $previousStage['uid']
773 ]);
774 return $result;
775 }
776
777 /**
778 * @param int $id Current Page id to select Workspace items from.
779 * @return array
780 */
781 public function sendPageToNextStage($id)
782 {
783 $workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
784 $this->stageService->getWorkspaceId(),
785 $filter = 1,
786 $stage = -99,
787 $id,
788 $recursionLevel = 0,
789 $selectionType = 'tables_modify'
790 );
791 list($currentStage, $nextStage) = $this->stageService->getNextStageForElementCollection($workspaceItemsArray);
792 // get only the relevant items for processing
793 $workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
794 $this->stageService->getWorkspaceId(),
795 $filter = 1,
796 $currentStage['uid'],
797 $id,
798 $recursionLevel = 0,
799 $selectionType = 'tables_modify'
800 );
801 $stageFormFields = $this->getSentToStageWindow($nextStage['uid']);
802 $result = array_merge($stageFormFields, [
803 'title' => 'Status message: Page send to next stage - ID: ' . $id . ' - Next stage title: ' . $nextStage['title'],
804 'affects' => $workspaceItemsArray,
805 'stageId' => $nextStage['uid']
806 ]);
807 return $result;
808 }
809
810 /**
811 * Fetch the current label and visible state of the buttons.
812 *
813 * @param int $id
814 * @return string The pre-rendered HTML for the stage buttons
815 */
816 public function updateStageChangeButtons($id)
817 {
818 // fetch the next and previous stage
819 $workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
820 $this->stageService->getWorkspaceId(),
821 $filter = 1,
822 $stage = -99,
823 $id,
824 $recursionLevel = 0,
825 $selectionType = 'tables_modify'
826 );
827 list(, $nextStage) = $this->stageService->getNextStageForElementCollection($workspaceItemsArray);
828 list(, $previousStage) = $this->stageService->getPreviousStageForElementCollection($workspaceItemsArray);
829
830 $view = GeneralUtility::makeInstance(StandaloneView::class);
831 $extensionPath = ExtensionManagementUtility::extPath('workspaces');
832 $view->setPartialRootPaths(['default' => $extensionPath . 'Resources/Private/Partials']);
833 $view->setTemplatePathAndFilename($extensionPath . 'Resources/Private/Templates/Preview/Ajax/StageButtons.html');
834 $request = $view->getRequest();
835 $request->setControllerExtensionName('workspaces');
836 $view->assignMultiple([
837 'enablePreviousStageButton' => is_array($previousStage) && !empty($previousStage),
838 'enableNextStageButton' => is_array($nextStage) && !empty($nextStage),
839 'enableDiscardStageButton' => is_array($nextStage) && !empty($nextStage) || is_array($previousStage) && !empty($previousStage),
840 'nextStage' => $nextStage['title'],
841 'nextStageId' => $nextStage['uid'],
842 'prevStage' => $previousStage['title'],
843 'prevStageId' => $previousStage['uid'],
844 ]);
845 $renderedView = $view->render();
846 return $renderedView;
847 }
848
849 /**
850 * @param int $workspaceId
851 * @return int Id of the original workspace
852 * @throws Exception
853 */
854 protected function setTemporaryWorkspace($workspaceId)
855 {
856 $workspaceId = (int)$workspaceId;
857 $currentWorkspace = (int)$this->getBackendUser()->workspace;
858
859 if ($currentWorkspace !== $workspaceId) {
860 if (!$this->getBackendUser()->setTemporaryWorkspace($workspaceId)) {
861 throw new Exception(
862 'Cannot set temporary workspace to "' . $workspaceId . '"',
863 1371484524
864 );
865 }
866 }
867
868 return $currentWorkspace;
869 }
870
871 /**
872 * @return BackendUserAuthentication
873 */
874 protected function getBackendUser()
875 {
876 return $GLOBALS['BE_USER'];
877 }
878
879 /**
880 * @return LanguageService
881 */
882 protected function getLanguageService()
883 {
884 return $GLOBALS['LANG'];
885 }
886
887 /**
888 * Gets an error response to be shown in the grid component.
889 *
890 * @param string $errorLabel Name of the label in the locallang.xlf file
891 * @param int $errorCode The error code to be used
892 * @param bool $successFlagValue Value of the success flag to be delivered back (might be FALSE in most cases)
893 * @return array
894 */
895 protected function getErrorResponse($errorLabel, $errorCode = 0, $successFlagValue = false)
896 {
897 $localLangFile = 'LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf';
898 $response = [
899 'error' => [
900 'code' => $errorCode,
901 'message' => $this->getLanguageService()->sL($localLangFile . ':' . $errorLabel)
902 ],
903 'success' => $successFlagValue
904 ];
905 return $response;
906 }
907
908 /**
909 * Gets the current workspace ID.
910 *
911 * @return int The current workspace ID
912 */
913 protected function getCurrentWorkspace()
914 {
915 return $this->workspaceService->getCurrentWorkspace();
916 }
917 }