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