‪TYPO3CMS  ‪main
ElementEntityProcessor.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
21 use TYPO3\CMS\Backend\Utility\BackendUtility;
26 
32 #[Autoconfigure(public: true, shared: false)]
34 {
35  protected int ‪$workspace;
37 
38  public function ‪__construct(
39  protected readonly ‪TcaSchemaFactory $tcaSchemaFactory
40  ) {}
41 
45  public function ‪setWorkspace(int ‪$workspace): void
46  {
47  $this->workspace = ‪$workspace;
48  }
49 
53  public function ‪getWorkspace(): int
54  {
55  return ‪$this->workspace;
56  }
57 
58  public function ‪getDataHandler(): ‪DataHandler
59  {
60  if (!isset($this->dataHandler)) {
61  $this->dataHandler = GeneralUtility::makeInstance(DataHandler::class);
62  }
63  return ‪$this->dataHandler;
64  }
65 
71  public function ‪transformDependentElementsToUseLiveId(array $elements): array
72  {
73  $transformedElements = [];
74  foreach ($elements as $element) {
75  $elementName = ‪ElementEntity::getIdentifier($element->getTable(), $element->getDataValue('liveId'));
76  $transformedElements[$elementName] = $element;
77  }
78  return $transformedElements;
79  }
80 
86  public function ‪createNewDependentElementChildReferenceCallback(array $callerArguments, array $targetArgument, ‪ElementEntity $caller, string $eventName): ?string
87  {
88  // skip children in case ancestor is invalid
89  if ($caller->‪isInvalid()) {
91  }
92  $schema = $this->tcaSchemaFactory->get($caller->‪getTable());
93  $fieldConfiguration = $schema->getField($callerArguments['field'])->getConfiguration();
94  $inlineFieldType = $this->‪getDataHandler()->getRelationFieldType($fieldConfiguration);
95  if (!$fieldConfiguration || ($fieldConfiguration['type'] !== 'flex' && $inlineFieldType !== 'field' && $inlineFieldType !== 'list')) {
97  }
98  return null;
99  }
100 
106  public function ‪createNewDependentElementParentReferenceCallback(array $callerArguments, array $targetArgument, ‪ElementEntity $caller, string $eventName): ?string
107  {
108  $schema = $this->tcaSchemaFactory->get($callerArguments['table']);
109  $fieldConfiguration = $schema->getField($callerArguments['field'])->getConfiguration();
110  $inlineFieldType = $this->‪getDataHandler()->getRelationFieldType($fieldConfiguration);
111  if (!$fieldConfiguration || ($fieldConfiguration['type'] !== 'flex' && $inlineFieldType !== 'field' && $inlineFieldType !== 'list')) {
113  }
114  return null;
115  }
116 
123  public function ‪createClearDependentElementChildReferenceCallback(array $callerArguments, array $targetArgument, ‪ElementEntity $caller, string $eventName): ?string
124  {
125  $response = $this->‪createNewDependentElementChildReferenceCallback($callerArguments, $targetArgument, $caller, $eventName);
126  if (empty($response)) {
127  ‪$record = BackendUtility::getRecord($callerArguments['table'], $callerArguments['id']);
128  if (‪VersionState::tryFrom(‪$record['t3ver_state'] ?? 0) !== VersionState::DELETE_PLACEHOLDER->value) {
130  }
131  }
132  return $response;
133  }
134 
141  public function ‪createClearDependentElementParentReferenceCallback(array $callerArguments, array $targetArgument, ‪ElementEntity $caller, string $eventName): ?string
142  {
143  $response = $this->‪createNewDependentElementParentReferenceCallback($callerArguments, $targetArgument, $caller, $eventName);
144  if (empty($response)) {
145  ‪$record = BackendUtility::getRecord($callerArguments['table'], $callerArguments['id']);
146  if (‪VersionState::tryFrom(‪$record['t3ver_state'] ?? 0) !== VersionState::DELETE_PLACEHOLDER->value) {
148  }
149  }
150  return $response;
151  }
152 
156  public function ‪createNewDependentElementCallback(array $callerArguments, array $targetArgument, ‪ElementEntity $caller, string $eventName): void
157  {
158  if (!BackendUtility::isTableWorkspaceEnabled($caller->‪getTable())) {
159  $caller->‪setInvalid(true);
160  return;
161  }
162 
163  $versionRecord = $caller->‪getRecord();
164  // If version record does not exist, it probably has been deleted (cleared from workspace), this means,
165  // that the reference index still has an old reference pointer, which is "fine" for deleted parents
166  if (empty($versionRecord)) {
167  throw new \RuntimeException(
168  'Element "' . $caller::getIdentifier($caller->‪getTable(), $caller->‪getId()) . '" does not exist',
169  1393960943
170  );
171  }
172 
173  $deleteFieldName = ‪$GLOBALS['TCA'][$caller->‪getTable()]['ctrl']['delete'] ?? null;
174  // If version is on live workspace, but an "offline" ID is set, mark the record as invalid.
175  // This happens if a change has been discarded (clearWSID) - it will be removed from the command map.
176  if (
177  (int)$versionRecord['t3ver_oid'] > 0 && (
178  (int)$versionRecord['t3ver_wsid'] === 0 // behavior prior to v10.1 (backward compatibility)
179  || !empty($deleteFieldName) && (int)$versionRecord['t3ver_wsid'] === $this->‪getWorkspace()
180  && (int)$versionRecord[$deleteFieldName] > 0 // behavior since v10.1
181  )
182  ) {
183  $caller->‪setDataValue('liveId', $caller->‪getId());
184  $caller->‪setInvalid(true);
185  return;
186  }
187  if ($caller->‪hasDataValue('liveId') === false) {
188  // Set the original uid from the version record
189  if (!empty($versionRecord['t3ver_oid']) && (int)$versionRecord['t3ver_wsid'] === $this->‪getWorkspace()) {
190  $caller->‪setDataValue('liveId', $versionRecord['t3ver_oid']);
191  } elseif ((int)$versionRecord['t3ver_wsid'] === 0 || (int)$versionRecord['t3ver_oid'] === 0) {
192  // The current version record is actually a live record or an accordant placeholder for live
193  $caller->‪setDataValue('liveId', $caller->‪getId());
194  $versionRecord = BackendUtility::getWorkspaceVersionOfRecord(
195  $this->‪getWorkspace(),
196  $caller->‪getTable(),
197  $caller->‪getId(),
198  'uid,t3ver_state'
199  );
200  // Set version uid to caller, most likely it's a delete placeholder
201  // for a child record that is not recognized in the reference index
202  if (!empty($versionRecord['uid'])) {
203  $caller->‪setId($versionRecord['uid']);
204  } else {
205  // If no version could be determined, mark record as invalid
206  // (thus, it will be removed from the command map)
207  $caller->‪setInvalid(true);
208  }
209  } else {
210  // In case of an unexpected record state, mark the record as invalid
211  $caller->‪setInvalid(true);
212  }
213  }
214  }
215 }
‪TYPO3\CMS\Core\DataHandling\DataHandler
Definition: DataHandler.php:104
‪TYPO3\CMS\Workspaces\Dependency\ElementEntity\RESPONSE_Skip
‪const RESPONSE_Skip
Definition: ElementEntity.php:36
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\createClearDependentElementChildReferenceCallback
‪string null createClearDependentElementChildReferenceCallback(array $callerArguments, array $targetArgument, ElementEntity $caller, string $eventName)
Definition: ElementEntityProcessor.php:123
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\__construct
‪__construct(protected readonly TcaSchemaFactory $tcaSchemaFactory)
Definition: ElementEntityProcessor.php:38
‪TYPO3\CMS\Core\Versioning\VersionState
‪VersionState
Definition: VersionState.php:22
‪TYPO3\CMS\Workspaces\Dependency\ElementEntity
Definition: ElementEntity.php:30
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\transformDependentElementsToUseLiveId
‪transformDependentElementsToUseLiveId(array $elements)
Definition: ElementEntityProcessor.php:71
‪TYPO3\CMS\Core\Schema\TcaSchemaFactory
Definition: TcaSchemaFactory.php:57
‪TYPO3\CMS\Frontend\Content\tryFrom
‪@ tryFrom
Definition: ContentSlideMode.php:27
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\createNewDependentElementChildReferenceCallback
‪string null createNewDependentElementChildReferenceCallback(array $callerArguments, array $targetArgument, ElementEntity $caller, string $eventName)
Definition: ElementEntityProcessor.php:86
‪TYPO3\CMS\Workspaces\Dependency\ElementEntity\setDataValue
‪setDataValue(string $key, mixed $value)
Definition: ElementEntity.php:116
‪TYPO3\CMS\Workspaces\Dependency\ElementEntity\getIdentifier
‪static getIdentifier(string $table, int $id)
Definition: ElementEntity.php:322
‪TYPO3\CMS\Workspaces\Dependency
Definition: DependencyEntityFactory.php:18
‪TYPO3\CMS\Workspaces\Dependency\ElementEntity\setInvalid
‪setInvalid(bool $invalid)
Definition: ElementEntity.php:59
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\getDataHandler
‪getDataHandler()
Definition: ElementEntityProcessor.php:58
‪TYPO3\CMS\Webhooks\Message\$record
‪identifier readonly int readonly array $record
Definition: PageModificationMessage.php:36
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\createNewDependentElementCallback
‪createNewDependentElementCallback(array $callerArguments, array $targetArgument, ElementEntity $caller, string $eventName)
Definition: ElementEntityProcessor.php:156
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\createNewDependentElementParentReferenceCallback
‪string null createNewDependentElementParentReferenceCallback(array $callerArguments, array $targetArgument, ElementEntity $caller, string $eventName)
Definition: ElementEntityProcessor.php:106
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor
Definition: ElementEntityProcessor.php:34
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\$workspace
‪int $workspace
Definition: ElementEntityProcessor.php:35
‪TYPO3\CMS\Workspaces\Dependency\ElementEntity\setId
‪setId(int $id)
Definition: ElementEntity.php:88
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\setWorkspace
‪setWorkspace(int $workspace)
Definition: ElementEntityProcessor.php:45
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\$dataHandler
‪DataHandler $dataHandler
Definition: ElementEntityProcessor.php:36
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\createClearDependentElementParentReferenceCallback
‪string null createClearDependentElementParentReferenceCallback(array $callerArguments, array $targetArgument, ElementEntity $caller, string $eventName)
Definition: ElementEntityProcessor.php:141
‪TYPO3\CMS\Workspaces\Dependency\ElementEntityProcessor\getWorkspace
‪getWorkspace()
Definition: ElementEntityProcessor.php:53
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Workspaces\Dependency\ElementEntity\getRecord
‪getRecord()
Definition: ElementEntity.php:330
‪TYPO3\CMS\Workspaces\Dependency\ElementEntity\isInvalid
‪isInvalid()
Definition: ElementEntity.php:64
‪TYPO3\CMS\Workspaces\Dependency\ElementEntity\getTable
‪getTable()
Definition: ElementEntity.php:72
‪TYPO3\CMS\Workspaces\Dependency\ElementEntity\getId
‪getId()
Definition: ElementEntity.php:80
‪TYPO3\CMS\Workspaces\Dependency\ElementEntity\hasDataValue
‪hasDataValue(string $key)
Definition: ElementEntity.php:124