[TASK] Improve duplicate exception code check
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Functional / DataHandling / Framework / ActionService.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Functional\DataHandling\Framework;
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\Database\ConnectionPool;
18 use TYPO3\CMS\Core\DataHandling\DataHandler;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Core\Utility\StringUtility;
21
22 /**
23 * DataHandler Actions
24 */
25 class ActionService
26 {
27 /**
28 * @var DataHandler
29 */
30 protected $dataHandler;
31
32 /**
33 * @return DataHandler
34 */
35 public function getDataHandler()
36 {
37 return $this->dataHandler;
38 }
39
40 /**
41 * @param string $tableName
42 * @param int $pageId
43 * @param array $recordData
44 * @return array
45 */
46 public function createNewRecord($tableName, $pageId, array $recordData)
47 {
48 return $this->createNewRecords($pageId, [$tableName => $recordData]);
49 }
50
51 /**
52 * @param int $pageId
53 * @param array $tableRecordData
54 * @return array
55 */
56 public function createNewRecords($pageId, array $tableRecordData)
57 {
58 $dataMap = [];
59 $newTableIds = [];
60 $currentUid = null;
61 $previousTableName = null;
62 $previousUid = null;
63 foreach ($tableRecordData as $tableName => $recordData) {
64 $recordData = $this->resolvePreviousUid($recordData, $currentUid);
65 if (!isset($recordData['pid'])) {
66 $recordData['pid'] = $pageId;
67 }
68 $currentUid = StringUtility::getUniqueId('NEW');
69 $newTableIds[$tableName][] = $currentUid;
70 $dataMap[$tableName][$currentUid] = $recordData;
71 if ($previousTableName !== null && $previousUid !== null) {
72 $dataMap[$previousTableName][$previousUid] = $this->resolveNextUid(
73 $dataMap[$previousTableName][$previousUid],
74 $currentUid
75 );
76 }
77 $previousTableName = $tableName;
78 $previousUid = $currentUid;
79 }
80 $this->createDataHandler();
81 $this->dataHandler->start($dataMap, []);
82 $this->dataHandler->process_datamap();
83
84 foreach ($newTableIds as $tableName => &$ids) {
85 foreach ($ids as &$id) {
86 if (!empty($this->dataHandler->substNEWwithIDs[$id])) {
87 $id = $this->dataHandler->substNEWwithIDs[$id];
88 }
89 }
90 }
91
92 return $newTableIds;
93 }
94
95 /**
96 * @param string $tableName
97 * @param int $uid
98 * @param array $recordData
99 * @param NULL|array $deleteTableRecordIds
100 */
101 public function modifyRecord($tableName, $uid, array $recordData, array $deleteTableRecordIds = null)
102 {
103 $dataMap = [
104 $tableName => [
105 $uid => $recordData,
106 ],
107 ];
108 $commandMap = [];
109 if (!empty($deleteTableRecordIds)) {
110 foreach ($deleteTableRecordIds as $tableName => $recordIds) {
111 foreach ($recordIds as $recordId) {
112 $commandMap[$tableName][$recordId]['delete'] = true;
113 }
114 }
115 }
116 $this->createDataHandler();
117 $this->dataHandler->start($dataMap, $commandMap);
118 $this->dataHandler->process_datamap();
119 if (!empty($commandMap)) {
120 $this->dataHandler->process_cmdmap();
121 }
122 }
123
124 /**
125 * @param int $pageId
126 * @param array $tableRecordData
127 */
128 public function modifyRecords($pageId, array $tableRecordData)
129 {
130 $dataMap = [];
131 $currentUid = null;
132 $previousTableName = null;
133 $previousUid = null;
134 foreach ($tableRecordData as $tableName => $recordData) {
135 if (empty($recordData['uid'])) {
136 continue;
137 }
138 $recordData = $this->resolvePreviousUid($recordData, $currentUid);
139 $currentUid = $recordData['uid'];
140 if ($recordData['uid'] === '__NEW') {
141 $recordData['pid'] = $pageId;
142 $currentUid = StringUtility::getUniqueId('NEW');
143 }
144 unset($recordData['uid']);
145 $dataMap[$tableName][$currentUid] = $recordData;
146 if ($previousTableName !== null && $previousUid !== null) {
147 $dataMap[$previousTableName][$previousUid] = $this->resolveNextUid(
148 $dataMap[$previousTableName][$previousUid],
149 $currentUid
150 );
151 }
152 $previousTableName = $tableName;
153 $previousUid = $currentUid;
154 }
155 $this->createDataHandler();
156 $this->dataHandler->start($dataMap, []);
157 $this->dataHandler->process_datamap();
158 }
159
160 /**
161 * @param string $tableName
162 * @param int $uid
163 * @return array
164 */
165 public function deleteRecord($tableName, $uid)
166 {
167 return $this->deleteRecords(
168 [
169 $tableName => [$uid],
170 ]
171 );
172 }
173
174 /**
175 * @param array $tableRecordIds
176 * @return array
177 */
178 public function deleteRecords(array $tableRecordIds)
179 {
180 $commandMap = [];
181 foreach ($tableRecordIds as $tableName => $ids) {
182 foreach ($ids as $uid) {
183 $commandMap[$tableName][$uid] = [
184 'delete' => true,
185 ];
186 }
187 }
188 $this->createDataHandler();
189 $this->dataHandler->start([], $commandMap);
190 $this->dataHandler->process_cmdmap();
191 // Deleting workspace records is actually a copy(!)
192 return $this->dataHandler->copyMappingArray;
193 }
194
195 /**
196 * @param string $tableName
197 * @param int $uid
198 */
199 public function clearWorkspaceRecord($tableName, $uid)
200 {
201 $this->clearWorkspaceRecords(
202 [
203 $tableName => [$uid],
204 ]
205 );
206 }
207
208 /**
209 * @param array $tableRecordIds
210 */
211 public function clearWorkspaceRecords(array $tableRecordIds)
212 {
213 $commandMap = [];
214 foreach ($tableRecordIds as $tableName => $ids) {
215 foreach ($ids as $uid) {
216 $commandMap[$tableName][$uid] = [
217 'version' => [
218 'action' => 'clearWSID',
219 ]
220 ];
221 }
222 }
223 $this->createDataHandler();
224 $this->dataHandler->start([], $commandMap);
225 $this->dataHandler->process_cmdmap();
226 }
227
228 /**
229 * @param string $tableName
230 * @param int $uid
231 * @param int $pageId
232 * @param NULL|array $recordData
233 * @return array
234 */
235 public function copyRecord($tableName, $uid, $pageId, array $recordData = null)
236 {
237 $commandMap = [
238 $tableName => [
239 $uid => [
240 'copy' => $pageId,
241 ],
242 ],
243 ];
244 if ($recordData !== null) {
245 $commandMap[$tableName][$uid]['copy'] = [
246 'action' => 'paste',
247 'target' => $pageId,
248 'update' => $recordData,
249 ];
250 }
251 $this->createDataHandler();
252 $this->dataHandler->start([], $commandMap);
253 $this->dataHandler->process_cmdmap();
254 return $this->dataHandler->copyMappingArray;
255 }
256
257 /**
258 * @param string $tableName
259 * @param int $uid
260 * @param int $pageId
261 * @param NULL|array $recordData
262 * @return array
263 */
264 public function moveRecord($tableName, $uid, $pageId, array $recordData = null)
265 {
266 $commandMap = [
267 $tableName => [
268 $uid => [
269 'move' => $pageId,
270 ],
271 ],
272 ];
273 if ($recordData !== null) {
274 $commandMap[$tableName][$uid]['move'] = [
275 'action' => 'paste',
276 'target' => $pageId,
277 'update' => $recordData,
278 ];
279 }
280 $this->createDataHandler();
281 $this->dataHandler->start([], $commandMap);
282 $this->dataHandler->process_cmdmap();
283 return $this->dataHandler->copyMappingArray;
284 }
285
286 /**
287 * @param string $tableName
288 * @param int $uid
289 * @param int $languageId
290 * @return array
291 */
292 public function localizeRecord($tableName, $uid, $languageId)
293 {
294 $commandMap = [
295 $tableName => [
296 $uid => [
297 'localize' => $languageId,
298 ],
299 ],
300 ];
301 $this->createDataHandler();
302 $this->dataHandler->start([], $commandMap);
303 $this->dataHandler->process_cmdmap();
304 return $this->dataHandler->copyMappingArray;
305 }
306
307 /**
308 * @param string $tableName
309 * @param int $uid
310 * @param string $fieldName
311 * @param array $referenceIds
312 */
313 public function modifyReferences($tableName, $uid, $fieldName, array $referenceIds)
314 {
315 $dataMap = [
316 $tableName => [
317 $uid => [
318 $fieldName => implode(',', $referenceIds),
319 ],
320 ]
321 ];
322 $this->createDataHandler();
323 $this->dataHandler->start($dataMap, []);
324 $this->dataHandler->process_datamap();
325 }
326
327 /**
328 * @param string $tableName
329 * @param int $liveUid
330 * @param bool $throwException
331 */
332 public function publishRecord($tableName, $liveUid, $throwException = true)
333 {
334 $this->publishRecords([$tableName => [$liveUid]], $throwException);
335 }
336
337 /**
338 * @param array $tableLiveUids
339 * @param bool $throwException
340 * @throws \TYPO3\CMS\Core\Tests\Exception
341 */
342 public function publishRecords(array $tableLiveUids, $throwException = true)
343 {
344 $commandMap = [];
345 foreach ($tableLiveUids as $tableName => $liveUids) {
346 foreach ($liveUids as $liveUid) {
347 $versionedUid = $this->getVersionedId($tableName, $liveUid);
348 if (empty($versionedUid)) {
349 if ($throwException) {
350 throw new \TYPO3\CMS\Core\Tests\Exception('Versioned UID could not be determined', 1476049592);
351 } else {
352 continue;
353 }
354 }
355
356 $commandMap[$tableName][$liveUid] = [
357 'version' => [
358 'action' => 'swap',
359 'swapWith' => $versionedUid,
360 'notificationAlternativeRecipients' => [],
361 ],
362 ];
363 }
364 }
365 $this->createDataHandler();
366 $this->dataHandler->start([], $commandMap);
367 $this->dataHandler->process_cmdmap();
368 }
369
370 /**
371 * @param int $workspaceId
372 */
373 public function publishWorkspace($workspaceId)
374 {
375 $commandMap = $this->getWorkspaceService()->getCmdArrayForPublishWS($workspaceId, false);
376 $this->createDataHandler();
377 $this->dataHandler->start([], $commandMap);
378 $this->dataHandler->process_cmdmap();
379 }
380
381 /**
382 * @param int $workspaceId
383 */
384 public function swapWorkspace($workspaceId)
385 {
386 $commandMap = $this->getWorkspaceService()->getCmdArrayForPublishWS($workspaceId, true);
387 $this->createDataHandler();
388 $this->dataHandler->start([], $commandMap);
389 $this->dataHandler->process_cmdmap();
390 }
391
392 /**
393 * @param array $recordData
394 * @param NULL|string|int $previousUid
395 * @return array
396 */
397 protected function resolvePreviousUid(array $recordData, $previousUid)
398 {
399 if ($previousUid === null) {
400 return $recordData;
401 }
402 foreach ($recordData as $fieldName => $fieldValue) {
403 if (strpos($fieldValue, '__previousUid') === false) {
404 continue;
405 }
406 $recordData[$fieldName] = str_replace('__previousUid', $previousUid, $fieldValue);
407 }
408 return $recordData;
409 }
410
411 /**
412 * @param array $recordData
413 * @param NULL|string|int $nextUid
414 * @return array
415 */
416 protected function resolveNextUid(array $recordData, $nextUid)
417 {
418 if ($nextUid === null) {
419 return $recordData;
420 }
421 foreach ($recordData as $fieldName => $fieldValue) {
422 if (strpos($fieldValue, '__nextUid') === false) {
423 continue;
424 }
425 $recordData[$fieldName] = str_replace('__nextUid', $nextUid, $fieldValue);
426 }
427 return $recordData;
428 }
429
430 /**
431 * @param string $tableName
432 * @param int $liveUid
433 * @param bool $useDeleteClause
434 * @return NULL|int
435 */
436 protected function getVersionedId($tableName, $liveUid, $useDeleteClause = false)
437 {
438 $versionedId = null;
439 $liveUid = (int)$liveUid;
440 $workspaceId = (int)$this->getBackendUser()->workspace;
441
442 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
443 ->getQueryBuilderForTable($tableName);
444 $queryBuilder->getRestrictions()->removeAll();
445 $statement = $queryBuilder
446 ->select('uid')
447 ->from($tableName)
448 ->where(
449 $queryBuilder->expr()->eq('pid', -1),
450 $queryBuilder->expr()->eq('t3ver_oid', $liveUid),
451 $queryBuilder->expr()->eq('t3ver_wsid', $workspaceId)
452 )
453 ->execute();
454
455 $row = $statement->fetch();
456 if (!empty($row['uid'])) {
457 $versionedId = (int)$row['uid'];
458 }
459 return $versionedId;
460 }
461
462 /**
463 * @return DataHandler
464 */
465 protected function createDataHandler()
466 {
467 $this->dataHandler = GeneralUtility::makeInstance(DataHandler::class);
468 $backendUser = $this->getBackendUser();
469 if (isset($backendUser->uc['copyLevels'])) {
470 $this->dataHandler->copyTree = $backendUser->uc['copyLevels'];
471 }
472 return $this->dataHandler;
473 }
474
475 /**
476 * @return \TYPO3\CMS\Workspaces\Service\WorkspaceService
477 */
478 protected function getWorkspaceService()
479 {
480 return GeneralUtility::makeInstance(
481 \TYPO3\CMS\Workspaces\Service\WorkspaceService::class
482 );
483 }
484
485 /**
486 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
487 */
488 protected function getBackendUser()
489 {
490 return $GLOBALS['BE_USER'];
491 }
492 }