[BUGFIX] Fix several typos in php comments
[Packages/TYPO3.CMS.git] / typo3 / sysext / workspaces / Classes / DataHandler / CommandMap.php
1 <?php
2 namespace TYPO3\CMS\Workspaces\DataHandler;
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\DataHandling\DataHandler;
19 use TYPO3\CMS\Core\Utility\ArrayUtility;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Core\Utility\MathUtility;
22 use TYPO3\CMS\Workspaces\Dependency\DependencyResolver;
23 use TYPO3\CMS\Workspaces\Dependency\ElementEntity;
24 use TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor;
25 use TYPO3\CMS\Workspaces\Dependency\EventCallback;
26 use TYPO3\CMS\Workspaces\Hook\DataHandlerHook;
27
28 /**
29 * Handles the \TYPO3\CMS\Core\DataHandling\DataHandler command map and is
30 * only used in combination with \TYPO3\CMS\Core\DataHandling\DataHandler
31 */
32 class CommandMap
33 {
34 const SCOPE_WorkspacesSwap = 'SCOPE_WorkspacesSwap';
35 const SCOPE_WorkspacesSetStage = 'SCOPE_WorkspacesSetStage';
36 const SCOPE_WorkspacesClear = 'SCOPE_WorkspacesClear';
37 const KEY_GetElementPropertiesCallback = 'KEY_GetElementPropertiesCallback';
38 const KEY_GetCommonPropertiesCallback = 'KEY_GetCommonPropertiesCallback';
39 const KEY_ElementConstructCallback = 'KEY_EventConstructCallback';
40 const KEY_ElementCreateChildReferenceCallback = 'KEY_ElementCreateChildReferenceCallback';
41 const KEY_ElementCreateParentReferenceCallback = 'KEY_ElementCreateParentReferenceCallback';
42 const KEY_UpdateGetIdCallback = 'KEY_UpdateGetIdCallback';
43 const KEY_TransformDependentElementsToUseLiveId = 'KEY_TransformDependentElementsToUseLiveId';
44
45 /**
46 * @var DataHandlerHook
47 */
48 protected $parent;
49
50 /**
51 * @var DataHandler
52 */
53 protected $tceMain;
54
55 /**
56 * @var array
57 */
58 protected $commandMap = [];
59
60 /**
61 * @var int
62 */
63 protected $workspace;
64
65 /**
66 * @var string
67 */
68 protected $workspacesSwapMode;
69
70 /**
71 * @var string
72 */
73 protected $workspacesChangeStageMode;
74
75 /**
76 * @var array
77 */
78 protected $scopes;
79
80 /**
81 * @var ElementEntityProcessor
82 */
83 protected $elementEntityProcessor;
84
85 /**
86 * Creates this object.
87 *
88 * @param DataHandlerHook $parent
89 * @param DataHandler $tceMain
90 * @param array $commandMap
91 * @param int $workspace
92 */
93 public function __construct(DataHandlerHook $parent, DataHandler $tceMain, array $commandMap, $workspace)
94 {
95 $this->setParent($parent);
96 $this->setTceMain($tceMain);
97 $this->set($commandMap);
98 $this->setWorkspace($workspace);
99 $this->setWorkspacesSwapMode($this->getTceMain()->BE_USER->getTSConfig()['options.']['workspaces.']['swapMode'] ?? '');
100 $this->setWorkspacesChangeStageMode($this->getTceMain()->BE_USER->getTSConfig()['options.']['workspaces.']['changeStageMode'] ?? '');
101 $this->constructScopes();
102 }
103
104 /**
105 * Gets the command map.
106 *
107 * @return array
108 */
109 public function get()
110 {
111 return $this->commandMap;
112 }
113
114 /**
115 * Sets the command map.
116 *
117 * @param array $commandMap
118 * @return CommandMap
119 */
120 public function set(array $commandMap)
121 {
122 $this->commandMap = $commandMap;
123 return $this;
124 }
125
126 /**
127 * Gets the parent object.
128 *
129 * @return DataHandlerHook
130 */
131 public function getParent()
132 {
133 return $this->parent;
134 }
135
136 /**
137 * Sets the parent object.
138 *
139 * @param DataHandlerHook $parent
140 * @return CommandMap
141 */
142 public function setParent(DataHandlerHook $parent)
143 {
144 $this->parent = $parent;
145 return $this;
146 }
147
148 /**
149 * Gets the parent object.
150 *
151 * @return DataHandler
152 */
153 public function getTceMain()
154 {
155 return $this->tceMain;
156 }
157
158 /**
159 * Sets the parent object.
160 *
161 * @param DataHandler $tceMain
162 * @return CommandMap
163 */
164 public function setTceMain(DataHandler $tceMain)
165 {
166 $this->tceMain = $tceMain;
167 return $this;
168 }
169
170 /**
171 * Sets the current workspace.
172 *
173 * @param int $workspace
174 */
175 public function setWorkspace($workspace)
176 {
177 $this->workspace = (int)$workspace;
178 }
179
180 /**
181 * Gets the current workspace.
182 *
183 * @return int
184 */
185 public function getWorkspace()
186 {
187 return $this->workspace;
188 }
189
190 /**
191 * Sets the workspaces swap mode
192 * (see options.workspaces.swapMode).
193 *
194 * @param string $workspacesSwapMode
195 * @return CommandMap
196 */
197 public function setWorkspacesSwapMode($workspacesSwapMode)
198 {
199 $this->workspacesSwapMode = (string)$workspacesSwapMode;
200 return $this;
201 }
202
203 /**
204 * Sets the workspaces change stage mode
205 * see options.workspaces.changeStageMode)
206 *
207 * @param string $workspacesChangeStageMode
208 * @return CommandMap
209 */
210 public function setWorkspacesChangeStageMode($workspacesChangeStageMode)
211 {
212 $this->workspacesChangeStageMode = (string)$workspacesChangeStageMode;
213 return $this;
214 }
215
216 /**
217 * Gets the element entity processor.
218 *
219 * @return ElementEntityProcessor
220 */
221 protected function getElementEntityProcessor()
222 {
223 if (!isset($this->elementEntityProcessor)) {
224 $this->elementEntityProcessor = GeneralUtility::makeInstance(ElementEntityProcessor::class);
225 $this->elementEntityProcessor->setWorkspace($this->getWorkspace());
226 }
227 return $this->elementEntityProcessor;
228 }
229
230 /**
231 * Processes the command map.
232 *
233 * @return CommandMap
234 */
235 public function process()
236 {
237 $this->resolveWorkspacesSwapDependencies();
238 $this->resolveWorkspacesSetStageDependencies();
239 $this->resolveWorkspacesClearDependencies();
240 return $this;
241 }
242
243 /**
244 * Invokes all items for swapping/publishing with a callback method.
245 *
246 * @param string $callbackMethod
247 * @param array $arguments Optional leading arguments for the callback method
248 */
249 protected function invokeWorkspacesSwapItems($callbackMethod, array $arguments = [])
250 {
251 // Traverses the cmd[] array and fetches the accordant actions:
252 foreach ($this->commandMap as $table => $liveIdCollection) {
253 foreach ($liveIdCollection as $liveId => $commandCollection) {
254 foreach ($commandCollection as $command => $properties) {
255 if ($command === 'version' && isset($properties['action']) && $properties['action'] === 'swap') {
256 if (isset($properties['swapWith']) && MathUtility::canBeInterpretedAsInteger($properties['swapWith'])) {
257 call_user_func_array([$this, $callbackMethod], array_merge($arguments, [$table, $liveId, $properties]));
258 }
259 }
260 }
261 }
262 }
263 }
264
265 /**
266 * Resolves workspaces related dependencies for swapping/publishing of the command map.
267 * Workspaces records that have children or (relative) parents which are versionized
268 * but not published with this request, are removed from the command map. Otherwise
269 * this would produce hanging record sets and lost references.
270 */
271 protected function resolveWorkspacesSwapDependencies()
272 {
273 $scope = self::SCOPE_WorkspacesSwap;
274 $dependency = $this->getDependencyUtility($scope);
275 if ($this->workspacesSwapMode === 'any' || $this->workspacesSwapMode === 'pages') {
276 $this->invokeWorkspacesSwapItems('applyWorkspacesSwapBehaviour');
277 }
278 $this->invokeWorkspacesSwapItems('addWorkspacesSwapElements', [$dependency]);
279 $this->applyWorkspacesDependencies($dependency, $scope);
280 }
281
282 /**
283 * Applies workspaces behaviour for swapping/publishing and takes care of the swapMode.
284 *
285 * @param string $table
286 * @param int $liveId
287 * @param array $properties
288 */
289 protected function applyWorkspacesSwapBehaviour($table, $liveId, array $properties)
290 {
291 $extendedCommandMap = [];
292 $elementList = [];
293 // Fetch accordant elements if the swapMode is 'any' or 'pages':
294 if ($this->workspacesSwapMode === 'any' || $this->workspacesSwapMode === 'pages' && $table === 'pages') {
295 $elementList = $this->getParent()->findPageElementsForVersionSwap($table, $liveId, $properties['swapWith']);
296 }
297 foreach ($elementList as $elementTable => $elementIdArray) {
298 foreach ($elementIdArray as $elementIds) {
299 $extendedCommandMap[$elementTable][$elementIds[0]]['version'] = array_merge($properties, ['swapWith' => $elementIds[1]]);
300 }
301 }
302 if (!empty($elementList)) {
303 $this->remove($table, $liveId, 'version');
304 $this->mergeToBottom($extendedCommandMap);
305 }
306 }
307
308 /**
309 * Adds workspaces elements for swapping/publishing.
310 *
311 * @param DependencyResolver $dependency
312 * @param string $table
313 * @param int $liveId
314 * @param array $properties
315 */
316 protected function addWorkspacesSwapElements(DependencyResolver $dependency, $table, $liveId, array $properties)
317 {
318 $elementList = [];
319 // Fetch accordant elements if the swapMode is 'any' or 'pages':
320 if ($this->workspacesSwapMode === 'any' || $this->workspacesSwapMode === 'pages' && $table === 'pages') {
321 $elementList = $this->getParent()->findPageElementsForVersionSwap($table, $liveId, $properties['swapWith']);
322 }
323 foreach ($elementList as $elementTable => $elementIdArray) {
324 foreach ($elementIdArray as $elementIds) {
325 $dependency->addElement($elementTable, $elementIds[1], ['liveId' => $elementIds[0], 'properties' => array_merge($properties, ['swapWith' => $elementIds[1]])]);
326 }
327 }
328 if (empty($elementList)) {
329 $dependency->addElement($table, $properties['swapWith'], ['liveId' => $liveId, 'properties' => $properties]);
330 }
331 }
332
333 /**
334 * Invokes all items for staging with a callback method.
335 *
336 * @param string $callbackMethod
337 * @param array $arguments Optional leading arguments for the callback method
338 */
339 protected function invokeWorkspacesSetStageItems($callbackMethod, array $arguments = [])
340 {
341 // Traverses the cmd[] array and fetches the accordant actions:
342 foreach ($this->commandMap as $table => $versionIdCollection) {
343 foreach ($versionIdCollection as $versionIdList => $commandCollection) {
344 foreach ($commandCollection as $command => $properties) {
345 if ($command === 'version' && isset($properties['action']) && $properties['action'] === 'setStage') {
346 if (isset($properties['stageId']) && MathUtility::canBeInterpretedAsInteger($properties['stageId'])) {
347 call_user_func_array([$this, $callbackMethod], array_merge($arguments, [$table, $versionIdList, $properties]));
348 }
349 }
350 }
351 }
352 }
353 }
354
355 /**
356 * Resolves workspaces related dependencies for staging of the command map.
357 * Workspaces records that have children or (relative) parents which are versionized
358 * but not staged with this request, are removed from the command map.
359 */
360 protected function resolveWorkspacesSetStageDependencies()
361 {
362 $scope = self::SCOPE_WorkspacesSetStage;
363 $dependency = $this->getDependencyUtility($scope);
364 if ($this->workspacesChangeStageMode === 'any' || $this->workspacesChangeStageMode === 'pages') {
365 $this->invokeWorkspacesSetStageItems('applyWorkspacesSetStageBehaviour');
366 }
367 $this->invokeWorkspacesSetStageItems('explodeSetStage');
368 $this->invokeWorkspacesSetStageItems('addWorkspacesSetStageElements', [$dependency]);
369 $this->applyWorkspacesDependencies($dependency, $scope);
370 }
371
372 /**
373 * Applies workspaces behaviour for staging and takes care of the changeStageMode.
374 *
375 * @param string $table
376 * @param string $versionIdList
377 * @param array $properties
378 */
379 protected function applyWorkspacesSetStageBehaviour($table, $versionIdList, array $properties)
380 {
381 $extendedCommandMap = [];
382 $versionIds = GeneralUtility::trimExplode(',', $versionIdList, true);
383 $elementList = [$table => $versionIds];
384 if ($this->workspacesChangeStageMode === 'any' || $this->workspacesChangeStageMode === 'pages') {
385 if (count($versionIds) === 1) {
386 $workspaceRecord = BackendUtility::getRecord($table, $versionIds[0], 't3ver_wsid');
387 $workspaceId = $workspaceRecord['t3ver_wsid'];
388 } else {
389 $workspaceId = $this->getWorkspace();
390 }
391 if ($table === 'pages') {
392 // Find all elements from the same ws to change stage
393 $livePageIds = $versionIds;
394 $this->getParent()->findRealPageIds($livePageIds);
395 $this->getParent()->findPageElementsForVersionStageChange($livePageIds, $workspaceId, $elementList);
396 } elseif ($this->workspacesChangeStageMode === 'any') {
397 // Find page to change stage:
398 $pageIdList = [];
399 $this->getParent()->findPageIdsForVersionStateChange($table, $versionIds, $workspaceId, $pageIdList, $elementList);
400 // Find other elements from the same ws to change stage:
401 $this->getParent()->findPageElementsForVersionStageChange($pageIdList, $workspaceId, $elementList);
402 }
403 }
404 foreach ($elementList as $elementTable => $elementIds) {
405 foreach ($elementIds as $elementId) {
406 $extendedCommandMap[$elementTable][$elementId]['version'] = $properties;
407 }
408 }
409 foreach ($versionIds as $versionId) {
410 $this->remove($table, $versionId, 'version');
411 }
412 $this->mergeToBottom($extendedCommandMap);
413 }
414
415 /**
416 * Adds workspaces elements for staging.
417 *
418 * @param DependencyResolver $dependency
419 * @param string $table
420 * @param string $versionId
421 * @param array $properties
422 */
423 protected function addWorkspacesSetStageElements(DependencyResolver $dependency, $table, $versionId, array $properties)
424 {
425 $dependency->addElement($table, $versionId, ['versionId' => $versionId, 'properties' => $properties]);
426 }
427
428 /**
429 * Resolves workspaces related dependencies for clearing/flushing of the command map.
430 * Workspaces records that have children or (relative) parents which are versionized
431 * but not cleared/flushed with this request, are removed from the command map.
432 */
433 protected function resolveWorkspacesClearDependencies()
434 {
435 $scope = self::SCOPE_WorkspacesClear;
436 $dependency = $this->getDependencyUtility($scope);
437 // Traverses the cmd[] array and fetches the accordant actions:
438 foreach ($this->commandMap as $table => $versionIdCollection) {
439 foreach ($versionIdCollection as $versionId => $commandCollection) {
440 foreach ($commandCollection as $command => $properties) {
441 if ($command === 'version' && isset($properties['action']) && ($properties['action'] === 'clearWSID' || $properties['action'] === 'flush')) {
442 $dependency->addElement($table, $versionId, ['versionId' => $versionId, 'properties' => $properties]);
443 }
444 }
445 }
446 }
447 $this->applyWorkspacesDependencies($dependency, $scope);
448 }
449
450 /**
451 * Explodes id-lists in the command map for staging actions.
452 *
453 * @throws \RuntimeException
454 * @param string $table
455 * @param string $versionIdList
456 * @param array $properties
457 */
458 protected function explodeSetStage($table, $versionIdList, array $properties)
459 {
460 $extractedCommandMap = [];
461 $versionIds = GeneralUtility::trimExplode(',', $versionIdList, true);
462 if (count($versionIds) > 1) {
463 foreach ($versionIds as $versionId) {
464 if (isset($this->commandMap[$table][$versionId]['version'])) {
465 throw new \RuntimeException('Command map for [' . $table . '][' . $versionId . '][version] was already set.', 1289391048);
466 }
467 $extractedCommandMap[$table][$versionId]['version'] = $properties;
468 $this->remove($table, $versionId, 'version');
469 }
470 $this->mergeToBottom($extractedCommandMap);
471 }
472 }
473
474 /**
475 * Applies the workspaces dependencies and removes incomplete structures or automatically
476 * completes them
477 *
478 * @param DependencyResolver $dependency
479 * @param string $scope
480 */
481 protected function applyWorkspacesDependencies(DependencyResolver $dependency, $scope)
482 {
483 $transformDependentElementsToUseLiveId = $this->getScopeData($scope, self::KEY_TransformDependentElementsToUseLiveId);
484 $elementsToBeVersioned = $dependency->getElements();
485 // Use the uid of the live record instead of the workspace record:
486 if ($transformDependentElementsToUseLiveId) {
487 $elementsToBeVersioned = $this->getElementEntityProcessor()->transformDependentElementsToUseLiveId($elementsToBeVersioned);
488 }
489 $outerMostParents = $dependency->getOuterMostParents();
490 /** @var ElementEntity $outerMostParent */
491 foreach ($outerMostParents as $outerMostParent) {
492 $dependentElements = $dependency->getNestedElements($outerMostParent);
493 if ($transformDependentElementsToUseLiveId) {
494 $dependentElements = $this->getElementEntityProcessor()->transformDependentElementsToUseLiveId($dependentElements);
495 }
496 // Gets the difference (intersection) between elements that were submitted by the user
497 // and the evaluation of all dependent records that should be used for this action instead:
498 $intersectingElements = array_intersect_key($dependentElements, $elementsToBeVersioned);
499 if (!empty($intersectingElements)) {
500 $this->update(current($intersectingElements), $dependentElements, $scope);
501 }
502 }
503 }
504
505 /**
506 * Updates the command map accordant to valid structures and takes care of the correct order.
507 *
508 * @param ElementEntity $intersectingElement
509 * @param array $elements
510 * @param string $scope
511 */
512 protected function update(ElementEntity $intersectingElement, array $elements, $scope)
513 {
514 $orderedCommandMap = [];
515 $commonProperties = [];
516 if ($this->getScopeData($scope, self::KEY_GetCommonPropertiesCallback)) {
517 $commonProperties = $this->processCallback($this->getScopeData($scope, self::KEY_GetCommonPropertiesCallback), [$intersectingElement]);
518 }
519 /** @var ElementEntity $element */
520 foreach ($elements as $element) {
521 $table = $element->getTable();
522 $id = $this->processCallback($this->getScopeData($scope, self::KEY_UpdateGetIdCallback), [$element]);
523 $this->remove($table, $id, 'version');
524 if ($element->isInvalid()) {
525 continue;
526 }
527 $orderedCommandMap[$table][$id]['version'] = $commonProperties;
528 if ($this->getScopeData($scope, self::KEY_GetElementPropertiesCallback)) {
529 $orderedCommandMap[$table][$id]['version'] = array_merge($commonProperties, $this->processCallback($this->getScopeData($scope, self::KEY_GetElementPropertiesCallback), [$element]));
530 }
531 }
532 // Ensure that ordered command map is on top of the command map:
533 $this->mergeToTop($orderedCommandMap);
534 }
535
536 /**
537 * Merges command map elements to the top of the current command map..
538 *
539 * @param array $commandMap
540 */
541 protected function mergeToTop(array $commandMap)
542 {
543 ArrayUtility::mergeRecursiveWithOverrule($commandMap, $this->commandMap);
544 $this->commandMap = $commandMap;
545 }
546
547 /**
548 * Merges command map elements to the bottom of the current command map.
549 *
550 * @param array $commandMap
551 */
552 protected function mergeToBottom(array $commandMap)
553 {
554 ArrayUtility::mergeRecursiveWithOverrule($this->commandMap, $commandMap);
555 }
556
557 /**
558 * Removes an element from the command map.
559 *
560 * @param string $table
561 * @param string $id
562 * @param string $command (optional)
563 */
564 protected function remove($table, $id, $command = null)
565 {
566 if (is_string($command)) {
567 unset($this->commandMap[$table][$id][$command]);
568 } else {
569 unset($this->commandMap[$table][$id]);
570 }
571 }
572
573 /**
574 * Callback to get the liveId of a dependent element.
575 *
576 * @param ElementEntity $element
577 * @return int
578 */
579 protected function getElementLiveIdCallback(ElementEntity $element)
580 {
581 return $element->getDataValue('liveId');
582 }
583
584 /**
585 * Callback to get the real id of a dependent element.
586 *
587 * @param ElementEntity $element
588 * @return int
589 */
590 protected function getElementIdCallback(ElementEntity $element)
591 {
592 return $element->getId();
593 }
594
595 /**
596 * Callback to get the specific properties of a dependent element for swapping/publishing.
597 *
598 * @param ElementEntity $element
599 * @return array
600 */
601 protected function getElementSwapPropertiesCallback(ElementEntity $element)
602 {
603 return [
604 'swapWith' => $element->getId()
605 ];
606 }
607
608 /**
609 * Callback to get common properties of dependent elements for clearing.
610 *
611 * @param ElementEntity $element
612 * @return array
613 */
614 protected function getCommonClearPropertiesCallback(ElementEntity $element)
615 {
616 $commonSwapProperties = [];
617 $elementProperties = $element->getDataValue('properties');
618 if (isset($elementProperties['action'])) {
619 $commonSwapProperties['action'] = $elementProperties['action'];
620 }
621 return $commonSwapProperties;
622 }
623
624 /**
625 * Callback to get common properties of dependent elements for swapping/publishing.
626 *
627 * @param ElementEntity $element
628 * @return array
629 */
630 protected function getCommonSwapPropertiesCallback(ElementEntity $element)
631 {
632 $commonSwapProperties = [];
633 $elementProperties = $element->getDataValue('properties');
634 if (isset($elementProperties['action'])) {
635 $commonSwapProperties['action'] = $elementProperties['action'];
636 }
637 if (isset($elementProperties['swapIntoWS'])) {
638 $commonSwapProperties['swapIntoWS'] = $elementProperties['swapIntoWS'];
639 }
640 if (isset($elementProperties['comment'])) {
641 $commonSwapProperties['comment'] = $elementProperties['comment'];
642 }
643 if (isset($elementProperties['notificationAlternativeRecipients'])) {
644 $commonSwapProperties['notificationAlternativeRecipients'] = $elementProperties['notificationAlternativeRecipients'];
645 }
646
647 return $commonSwapProperties;
648 }
649
650 /**
651 * Callback to get the specific properties of a dependent element for staging.
652 *
653 * @param ElementEntity $element
654 * @return array
655 */
656 protected function getElementSetStagePropertiesCallback(ElementEntity $element)
657 {
658 return $this->getCommonSetStagePropertiesCallback($element);
659 }
660
661 /**
662 * Callback to get common properties of dependent elements for staging.
663 *
664 * @param ElementEntity $element
665 * @return array
666 */
667 protected function getCommonSetStagePropertiesCallback(ElementEntity $element)
668 {
669 $commonSetStageProperties = [];
670 $elementProperties = $element->getDataValue('properties');
671 if (isset($elementProperties['stageId'])) {
672 $commonSetStageProperties['stageId'] = $elementProperties['stageId'];
673 }
674 if (isset($elementProperties['comment'])) {
675 $commonSetStageProperties['comment'] = $elementProperties['comment'];
676 }
677 if (isset($elementProperties['action'])) {
678 $commonSetStageProperties['action'] = $elementProperties['action'];
679 }
680 if (isset($elementProperties['notificationAlternativeRecipients'])) {
681 $commonSetStageProperties['notificationAlternativeRecipients'] = $elementProperties['notificationAlternativeRecipients'];
682 }
683 return $commonSetStageProperties;
684 }
685
686 /**
687 * Gets an instance of the dependency resolver utility.
688 *
689 * @param string $scope Scope identifier
690 * @return DependencyResolver
691 */
692 protected function getDependencyUtility($scope)
693 {
694 $dependency = GeneralUtility::makeInstance(DependencyResolver::class);
695 $dependency->setWorkspace($this->getWorkspace());
696 $dependency->setOuterMostParentsRequireReferences(true);
697 if ($this->getScopeData($scope, self::KEY_ElementConstructCallback)) {
698 $dependency->setEventCallback(ElementEntity::EVENT_Construct, $this->getDependencyCallback($this->getScopeData($scope, self::KEY_ElementConstructCallback)));
699 }
700 if ($this->getScopeData($scope, self::KEY_ElementCreateChildReferenceCallback)) {
701 $dependency->setEventCallback(ElementEntity::EVENT_CreateChildReference, $this->getDependencyCallback($this->getScopeData($scope, self::KEY_ElementCreateChildReferenceCallback)));
702 }
703 if ($this->getScopeData($scope, self::KEY_ElementCreateParentReferenceCallback)) {
704 $dependency->setEventCallback(ElementEntity::EVENT_CreateParentReference, $this->getDependencyCallback($this->getScopeData($scope, self::KEY_ElementCreateParentReferenceCallback)));
705 }
706 return $dependency;
707 }
708
709 /**
710 * Constructs the scope settings.
711 * Currently the scopes for swapping/publishing and staging are available.
712 */
713 protected function constructScopes()
714 {
715 $this->scopes = [
716 // settings for publishing and swapping:
717 self::SCOPE_WorkspacesSwap => [
718 // callback functions used to modify the commandMap
719 // + element properties are specific for each element
720 // + common properties are the same for all elements
721 self::KEY_GetElementPropertiesCallback => 'getElementSwapPropertiesCallback',
722 self::KEY_GetCommonPropertiesCallback => 'getCommonSwapPropertiesCallback',
723 // callback function used, when a new element to be checked is added
724 self::KEY_ElementConstructCallback => 'createNewDependentElementCallback',
725 // callback function used to determine whether an element is a valid child or parent reference (e.g. IRRE)
726 self::KEY_ElementCreateChildReferenceCallback => 'createNewDependentElementChildReferenceCallback',
727 self::KEY_ElementCreateParentReferenceCallback => 'createNewDependentElementParentReferenceCallback',
728 // callback function used to fetch the correct record uid on modifying the commandMap
729 self::KEY_UpdateGetIdCallback => 'getElementLiveIdCallback',
730 // setting whether to use the uid of the live record instead of the workspace record
731 self::KEY_TransformDependentElementsToUseLiveId => true
732 ],
733 // settings for modifying the stage:
734 self::SCOPE_WorkspacesSetStage => [
735 // callback functions used to modify the commandMap
736 // + element properties are specific for each element
737 // + common properties are the same for all elements
738 self::KEY_GetElementPropertiesCallback => 'getElementSetStagePropertiesCallback',
739 self::KEY_GetCommonPropertiesCallback => 'getCommonSetStagePropertiesCallback',
740 // callback function used, when a new element to be checked is added
741 self::KEY_ElementConstructCallback => null,
742 // callback function used to determine whether an element is a valid child or parent reference (e.g. IRRE)
743 self::KEY_ElementCreateChildReferenceCallback => 'createNewDependentElementChildReferenceCallback',
744 self::KEY_ElementCreateParentReferenceCallback => 'createNewDependentElementParentReferenceCallback',
745 // callback function used to fetch the correct record uid on modifying the commandMap
746 self::KEY_UpdateGetIdCallback => 'getElementIdCallback',
747 // setting whether to use the uid of the live record instead of the workspace record
748 self::KEY_TransformDependentElementsToUseLiveId => false
749 ],
750 // settings for clearing and flushing:
751 self::SCOPE_WorkspacesClear => [
752 // callback functions used to modify the commandMap
753 // + element properties are specific for each element
754 // + common properties are the same for all elements
755 self::KEY_GetElementPropertiesCallback => null,
756 self::KEY_GetCommonPropertiesCallback => 'getCommonClearPropertiesCallback',
757 // callback function used, when a new element to be checked is added
758 self::KEY_ElementConstructCallback => null,
759 // callback function used to determine whether an element is a valid child or parent reference (e.g. IRRE)
760 self::KEY_ElementCreateChildReferenceCallback => 'createClearDependentElementChildReferenceCallback',
761 self::KEY_ElementCreateParentReferenceCallback => 'createClearDependentElementParentReferenceCallback',
762 // callback function used to fetch the correct record uid on modifying the commandMap
763 self::KEY_UpdateGetIdCallback => 'getElementIdCallback',
764 // setting whether to use the uid of the live record instead of the workspace record
765 self::KEY_TransformDependentElementsToUseLiveId => false
766 ]
767 ];
768 }
769
770 /**
771 * Gets data for a particular scope.
772 *
773 * @throws \RuntimeException
774 * @param string $scope Scope identifier
775 * @param string $key
776 * @return string
777 */
778 protected function getScopeData($scope, $key)
779 {
780 if (!isset($this->scopes[$scope])) {
781 throw new \RuntimeException('Scope "' . $scope . '" is not defined.', 1289342187);
782 }
783 return $this->scopes[$scope][$key];
784 }
785
786 /**
787 * Gets a new callback to be used in the dependency resolver utility.
788 *
789 * @param string $method
790 * @param array $targetArguments
791 * @return EventCallback
792 */
793 protected function getDependencyCallback($method, array $targetArguments = [])
794 {
795 return GeneralUtility::makeInstance(
796 EventCallback::class,
797 $this->getElementEntityProcessor(),
798 $method,
799 $targetArguments
800 );
801 }
802
803 /**
804 * Processes a local callback inside this object.
805 *
806 * @param string $method
807 * @param array $callbackArguments
808 * @return mixed
809 */
810 protected function processCallback($method, array $callbackArguments)
811 {
812 return call_user_func_array([$this, $method], $callbackArguments);
813 }
814 }