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