2 namespace TYPO3\CMS\Version\DataHandler;
111 public function get()
238 if (!isset($this->elementEntityProcessor)) {
240 \TYPO3\CMS\Version\Dependency\ElementEntityProcessor::class
242 $this->elementEntityProcessor->setWorkspace($this->
getWorkspace());
270 foreach ($this->commandMap as $table => $liveIdCollection) {
271 foreach ($liveIdCollection as $liveId => $commandCollection) {
272 foreach ($commandCollection as $command => $properties) {
273 if ($command ===
'version' && isset($properties[
'action']) && $properties[
'action'] ===
'swap') {
274 if (isset($properties[
'swapWith']) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($properties[
'swapWith'])) {
275 call_user_func_array(array($this, $callbackMethod), array_merge($arguments, array($table, $liveId, $properties)));
293 $scope = self::SCOPE_WorkspacesSwap;
294 $dependency = $this->getDependencyUtility($scope);
299 $this->applyWorkspacesDependencies($dependency, $scope);
312 $extendedCommandMap = array();
313 $elementList = array();
315 if ($this->workspacesSwapMode ===
'any' || $this->workspacesSwapMode ===
'pages' && $table ===
'pages') {
316 $elementList = $this->
getParent()->findPageElementsForVersionSwap($table, $liveId, $properties[
'swapWith']);
318 foreach ($elementList as $elementTable => $elementIdArray) {
319 foreach ($elementIdArray as $elementIds) {
320 $extendedCommandMap[$elementTable][$elementIds[0]][
'version'] = array_merge($properties, array(
'swapWith' => $elementIds[1]));
323 if (!empty($elementList)) {
324 $this->
remove($table, $liveId,
'version');
338 protected function addWorkspacesSwapElements(\TYPO3\CMS\Version\Dependency\DependencyResolver $dependency, $table, $liveId, array $properties)
340 $elementList = array();
342 if ($this->workspacesSwapMode ===
'any' || $this->workspacesSwapMode ===
'pages' && $table ===
'pages') {
343 $elementList = $this->
getParent()->findPageElementsForVersionSwap($table, $liveId, $properties[
'swapWith']);
345 foreach ($elementList as $elementTable => $elementIdArray) {
346 foreach ($elementIdArray as $elementIds) {
347 $dependency->addElement($elementTable, $elementIds[1], array(
'liveId' => $elementIds[0],
'properties' => array_merge($properties, array(
'swapWith' => $elementIds[1]))));
350 if (empty($elementList)) {
351 $dependency->addElement($table, $properties[
'swapWith'], array(
'liveId' => $liveId,
'properties' => $properties));
365 foreach ($this->commandMap as $table => $versionIdCollection) {
366 foreach ($versionIdCollection as $versionIdList => $commandCollection) {
367 foreach ($commandCollection as $command => $properties) {
368 if ($command ===
'version' && isset($properties[
'action']) && $properties[
'action'] ===
'setStage') {
369 if (isset($properties[
'stageId']) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($properties[
'stageId'])) {
370 call_user_func_array(array($this, $callbackMethod), array_merge($arguments, array($table, $versionIdList, $properties)));
387 $scope = self::SCOPE_WorkspacesSetStage;
388 $dependency = $this->getDependencyUtility($scope);
394 $this->applyWorkspacesDependencies($dependency, $scope);
407 $extendedCommandMap = array();
409 $elementList = array($table => $versionIds);
411 if (count($versionIds) === 1) {
413 $workspaceId = $workspaceRecord[
't3ver_wsid'];
417 if ($table ===
'pages') {
419 $livePageIds = $versionIds;
420 $this->
getParent()->findRealPageIds($livePageIds);
421 $this->
getParent()->findPageElementsForVersionStageChange($livePageIds, $workspaceId, $elementList);
422 }
elseif ($this->workspacesChangeStageMode ===
'any') {
424 $pageIdList = array();
425 $this->
getParent()->findPageIdsForVersionStateChange($table, $versionIds, $workspaceId, $pageIdList, $elementList);
427 $this->
getParent()->findPageElementsForVersionStageChange($pageIdList, $workspaceId, $elementList);
430 foreach ($elementList as $elementTable => $elementIds) {
431 foreach ($elementIds as $elementId) {
432 $extendedCommandMap[$elementTable][$elementId][
'version'] = $properties;
435 $this->
remove($table, $versionIds,
'version');
450 $dependency->addElement($table, $versionId, array(
'versionId' => $versionId,
'properties' => $properties));
462 $scope = self::SCOPE_WorkspacesClear;
463 $dependency = $this->getDependencyUtility($scope);
465 foreach ($this->commandMap as $table => $versionIdCollection) {
466 foreach ($versionIdCollection as $versionId => $commandCollection) {
467 foreach ($commandCollection as $command => $properties) {
468 if ($command ===
'version' && isset($properties[
'action']) && ($properties[
'action'] ===
'clearWSID' || $properties[
'action'] ===
'flush')) {
469 $dependency->addElement($table, $versionId, array(
'versionId' => $versionId,
'properties' => $properties));
474 $this->applyWorkspacesDependencies($dependency, $scope);
488 $extractedCommandMap = array();
490 if (count($versionIds) > 1) {
491 foreach ($versionIds as $versionId) {
492 if (isset($this->commandMap[$table][$versionId][
'version'])) {
493 throw new \RuntimeException(
'Command map for [' . $table .
'][' . $versionId .
'][version] was already set.', 1289391048);
495 $extractedCommandMap[$table][$versionId][
'version'] = $properties;
497 $this->
remove($table, $versionIdList,
'version');
510 protected function applyWorkspacesDependencies(\TYPO3\CMS\Version\Dependency\DependencyResolver $dependency, $scope)
512 $transformDependentElementsToUseLiveId = $this->
getScopeData($scope, self::KEY_TransformDependentElementsToUseLiveId);
513 $elementsToBeVersioned = $dependency->getElements();
515 if ($transformDependentElementsToUseLiveId) {
516 $elementsToBeVersioned = $this->
getElementEntityProcessor()->transformDependentElementsToUseLiveId($elementsToBeVersioned);
518 $outerMostParents = $dependency->getOuterMostParents();
520 foreach ($outerMostParents as $outerMostParent) {
521 $dependentElements = $dependency->getNestedElements($outerMostParent);
522 if ($transformDependentElementsToUseLiveId) {
527 $intersectingElements = array_intersect_key($dependentElements, $elementsToBeVersioned);
528 if (!empty($intersectingElements)) {
530 if (count($intersectingElements) !== count($dependentElements) && $this->workspacesConsiderReferences ===
false) {
531 $this->purgeWithErrorMessage($intersectingElements, $scope);
533 $this->update(current($intersectingElements), $dependentElements, $scope);
546 protected function purgeWithErrorMessage(array $elements, $scope)
549 foreach ($elements as $element) {
550 $table = $element->getTable();
552 $this->
remove($table, $id,
'version');
553 $this->
getTceMain()->log($table, $id, 5, 0, 1, $this->
getScopeData($scope, self::KEY_ScopeErrorMessage), $this->
getScopeData($scope, self::KEY_ScopeErrorCode), array(
569 protected function update(ElementEntity $intersectingElement, array $elements, $scope)
571 $orderedCommandMap = array();
572 $commonProperties = array();
573 if ($this->
getScopeData($scope, self::KEY_GetCommonPropertiesCallback)) {
574 $commonProperties = $this->
processCallback($this->
getScopeData($scope, self::KEY_GetCommonPropertiesCallback), array($intersectingElement));
577 foreach ($elements as $element) {
578 $table = $element->getTable();
580 $this->
remove($table, $id,
'version');
581 if ($element->isInvalid()) {
584 $orderedCommandMap[$table][$id][
'version'] = $commonProperties;
585 if ($this->
getScopeData($scope, self::KEY_GetElementPropertiesCallback)) {
586 $orderedCommandMap[$table][$id][
'version'] = array_merge($commonProperties, $this->
processCallback($this->
getScopeData($scope, self::KEY_GetElementPropertiesCallback), array($element)));
601 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($commandMap, $this->commandMap);
613 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($this->commandMap, $commandMap);
624 protected function remove($table, $id, $command = null)
626 if (is_string($command)) {
627 unset($this->commandMap[$table][$id][$command]);
629 unset($this->commandMap[$table][$id]);
652 return $element->
getId();
664 'swapWith' => $element->
getId()
676 $commonSwapProperties = array();
677 $elementProperties = $element->
getDataValue(
'properties');
678 if (isset($elementProperties[
'action'])) {
679 $commonSwapProperties[
'action'] = $elementProperties[
'action'];
681 return $commonSwapProperties;
692 $commonSwapProperties = array();
693 $elementProperties = $element->
getDataValue(
'properties');
694 if (isset($elementProperties[
'action'])) {
695 $commonSwapProperties[
'action'] = $elementProperties[
'action'];
697 if (isset($elementProperties[
'swapIntoWS'])) {
698 $commonSwapProperties[
'swapIntoWS'] = $elementProperties[
'swapIntoWS'];
700 if (isset($elementProperties[
'comment'])) {
701 $commonSwapProperties[
'comment'] = $elementProperties[
'comment'];
703 if (isset($elementProperties[
'notificationAlternativeRecipients'])) {
704 $commonSwapProperties[
'notificationAlternativeRecipients'] = $elementProperties[
'notificationAlternativeRecipients'];
707 return $commonSwapProperties;
729 $commonSetStageProperties = array();
730 $elementProperties = $element->
getDataValue(
'properties');
731 if (isset($elementProperties[
'stageId'])) {
732 $commonSetStageProperties[
'stageId'] = $elementProperties[
'stageId'];
734 if (isset($elementProperties[
'comment'])) {
735 $commonSetStageProperties[
'comment'] = $elementProperties[
'comment'];
737 if (isset($elementProperties[
'action'])) {
738 $commonSetStageProperties[
'action'] = $elementProperties[
'action'];
740 if (isset($elementProperties[
'notificationAlternativeRecipients'])) {
741 $commonSetStageProperties[
'notificationAlternativeRecipients'] = $elementProperties[
'notificationAlternativeRecipients'];
743 return $commonSetStageProperties;
752 protected function getDependencyUtility($scope)
757 $dependency->setOuterMostParentsRequireReferences(
true);
758 if ($this->
getScopeData($scope, self::KEY_ElementConstructCallback)) {
761 if ($this->
getScopeData($scope, self::KEY_ElementCreateChildReferenceCallback)) {
764 if ($this->
getScopeData($scope, self::KEY_ElementCreateParentReferenceCallback)) {
778 $this->scopes = array(
780 self::SCOPE_WorkspacesSwap => array(
782 self::KEY_ScopeErrorMessage =>
'Record "%s" (%s:%s) cannot be swapped or published independently, because it is related to other new or modified records.',
783 self::KEY_ScopeErrorCode => 1288283630,
787 self::KEY_GetElementPropertiesCallback =>
'getElementSwapPropertiesCallback',
788 self::KEY_GetCommonPropertiesCallback =>
'getCommonSwapPropertiesCallback',
790 self::KEY_ElementConstructCallback =>
'createNewDependentElementCallback',
792 self::KEY_ElementCreateChildReferenceCallback =>
'createNewDependentElementChildReferenceCallback',
793 self::KEY_ElementCreateParentReferenceCallback =>
'createNewDependentElementParentReferenceCallback',
795 self::KEY_PurgeWithErrorMessageGetIdCallback =>
'getElementLiveIdCallback',
797 self::KEY_UpdateGetIdCallback =>
'getElementLiveIdCallback',
799 self::KEY_TransformDependentElementsToUseLiveId =>
true
802 self::SCOPE_WorkspacesSetStage => array(
804 self::KEY_ScopeErrorMessage =>
'Record "%s" (%s:%s) cannot be sent to another stage independently, because it is related to other new or modified records.',
805 self::KEY_ScopeErrorCode => 1289342524,
809 self::KEY_GetElementPropertiesCallback =>
'getElementSetStagePropertiesCallback',
810 self::KEY_GetCommonPropertiesCallback =>
'getCommonSetStagePropertiesCallback',
812 self::KEY_ElementConstructCallback => null,
814 self::KEY_ElementCreateChildReferenceCallback =>
'createNewDependentElementChildReferenceCallback',
815 self::KEY_ElementCreateParentReferenceCallback =>
'createNewDependentElementParentReferenceCallback',
817 self::KEY_PurgeWithErrorMessageGetIdCallback =>
'getElementIdCallback',
819 self::KEY_UpdateGetIdCallback =>
'getElementIdCallback',
821 self::KEY_TransformDependentElementsToUseLiveId =>
false
824 self::SCOPE_WorkspacesClear => array(
826 self::KEY_ScopeErrorMessage =>
'Record "%s" (%s:%s) cannot be flushed independently, because it is related to other new or modified records.',
827 self::KEY_ScopeErrorCode => 1300467990,
831 self::KEY_GetElementPropertiesCallback => null,
832 self::KEY_GetCommonPropertiesCallback =>
'getCommonClearPropertiesCallback',
834 self::KEY_ElementConstructCallback => null,
836 self::KEY_ElementCreateChildReferenceCallback =>
'createClearDependentElementChildReferenceCallback',
837 self::KEY_ElementCreateParentReferenceCallback =>
'createClearDependentElementParentReferenceCallback',
839 self::KEY_PurgeWithErrorMessageGetIdCallback =>
'getElementIdCallback',
841 self::KEY_UpdateGetIdCallback =>
'getElementIdCallback',
843 self::KEY_TransformDependentElementsToUseLiveId =>
false
858 if (!isset($this->scopes[$scope])) {
859 throw new \RuntimeException(
'Scope "' . $scope .
'" is not defined.', 1289342187);
861 return $this->scopes[$scope][$key];
874 \TYPO3\CMS\Version\Dependency\EventCallback::class,
890 return call_user_func_array(array($this, $method), $callbackArguments);