8e634b11c89337a807f4791ef016e0c695d79cec
[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 int $languageId
311 * @return array
312 */
313 public function copyRecordToLanguage($tableName, $uid, $languageId)
314 {
315 $commandMap = [
316 $tableName => [
317 $uid => [
318 'copyToLanguage' => $languageId,
319 ],
320 ],
321 ];
322 $this->createDataHandler();
323 $this->dataHandler->start([], $commandMap);
324 $this->dataHandler->process_cmdmap();
325 return $this->dataHandler->copyMappingArray;
326 }
327
328 /**
329 * @param string $tableName
330 * @param int $uid
331 * @param string $fieldName
332 * @param array $referenceIds
333 */
334 public function modifyReferences($tableName, $uid, $fieldName, array $referenceIds)
335 {
336 $dataMap = [
337 $tableName => [
338 $uid => [
339 $fieldName => implode(',', $referenceIds),
340 ],
341 ]
342 ];
343 $this->createDataHandler();
344 $this->dataHandler->start($dataMap, []);
345 $this->dataHandler->process_datamap();
346 }
347
348 /**
349 * @param string $tableName
350 * @param int $liveUid
351 * @param bool $throwException
352 */
353 public function publishRecord($tableName, $liveUid, $throwException = true)
354 {
355 $this->publishRecords([$tableName => [$liveUid]], $throwException);
356 }
357
358 /**
359 * @param array $tableLiveUids
360 * @param bool $throwException
361 * @throws \TYPO3\TestingFramework\Core\Exception
362 */
363 public function publishRecords(array $tableLiveUids, $throwException = true)
364 {
365 $commandMap = [];
366 foreach ($tableLiveUids as $tableName => $liveUids) {
367 foreach ($liveUids as $liveUid) {
368 $versionedUid = $this->getVersionedId($tableName, $liveUid);
369 if (empty($versionedUid)) {
370 if ($throwException) {
371 throw new \TYPO3\TestingFramework\Core\Exception('Versioned UID could not be determined', 1476049592);
372 } else {
373 continue;
374 }
375 }
376
377 $commandMap[$tableName][$liveUid] = [
378 'version' => [
379 'action' => 'swap',
380 'swapWith' => $versionedUid,
381 'notificationAlternativeRecipients' => [],
382 ],
383 ];
384 }
385 }
386 $this->createDataHandler();
387 $this->dataHandler->start([], $commandMap);
388 $this->dataHandler->process_cmdmap();
389 }
390
391 /**
392 * @param int $workspaceId
393 */
394 public function publishWorkspace($workspaceId)
395 {
396 $commandMap = $this->getWorkspaceService()->getCmdArrayForPublishWS($workspaceId, false);
397 $this->createDataHandler();
398 $this->dataHandler->start([], $commandMap);
399 $this->dataHandler->process_cmdmap();
400 }
401
402 /**
403 * @param int $workspaceId
404 */
405 public function swapWorkspace($workspaceId)
406 {
407 $commandMap = $this->getWorkspaceService()->getCmdArrayForPublishWS($workspaceId, true);
408 $this->createDataHandler();
409 $this->dataHandler->start([], $commandMap);
410 $this->dataHandler->process_cmdmap();
411 }
412
413 /**
414 * @param array $recordData
415 * @param NULL|string|int $previousUid
416 * @return array
417 */
418 protected function resolvePreviousUid(array $recordData, $previousUid)
419 {
420 if ($previousUid === null) {
421 return $recordData;
422 }
423 foreach ($recordData as $fieldName => $fieldValue) {
424 if (strpos($fieldValue, '__previousUid') === false) {
425 continue;
426 }
427 $recordData[$fieldName] = str_replace('__previousUid', $previousUid, $fieldValue);
428 }
429 return $recordData;
430 }
431
432 /**
433 * @param array $recordData
434 * @param NULL|string|int $nextUid
435 * @return array
436 */
437 protected function resolveNextUid(array $recordData, $nextUid)
438 {
439 if ($nextUid === null) {
440 return $recordData;
441 }
442 foreach ($recordData as $fieldName => $fieldValue) {
443 if (strpos($fieldValue, '__nextUid') === false) {
444 continue;
445 }
446 $recordData[$fieldName] = str_replace('__nextUid', $nextUid, $fieldValue);
447 }
448 return $recordData;
449 }
450
451 /**
452 * @param string $tableName
453 * @param int $liveUid
454 * @return NULL|int
455 */
456 protected function getVersionedId($tableName, $liveUid)
457 {
458 $versionedId = null;
459 $liveUid = (int)$liveUid;
460 $workspaceId = (int)$this->getBackendUser()->workspace;
461
462 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
463 ->getQueryBuilderForTable($tableName);
464 $queryBuilder->getRestrictions()->removeAll();
465 $statement = $queryBuilder
466 ->select('uid')
467 ->from($tableName)
468 ->where(
469 $queryBuilder->expr()->eq(
470 'pid',
471 $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)
472 ),
473 $queryBuilder->expr()->eq(
474 't3ver_oid',
475 $queryBuilder->createNamedParameter($liveUid, \PDO::PARAM_INT)
476 ),
477 $queryBuilder->expr()->eq(
478 't3ver_wsid',
479 $queryBuilder->createNamedParameter($workspaceId, \PDO::PARAM_INT)
480 )
481 )
482 ->execute();
483
484 $row = $statement->fetch();
485 if (!empty($row['uid'])) {
486 $versionedId = (int)$row['uid'];
487 }
488 return $versionedId;
489 }
490
491 /**
492 * @return DataHandler
493 */
494 protected function createDataHandler()
495 {
496 $this->dataHandler = GeneralUtility::makeInstance(DataHandler::class);
497 $backendUser = $this->getBackendUser();
498 if (isset($backendUser->uc['copyLevels'])) {
499 $this->dataHandler->copyTree = $backendUser->uc['copyLevels'];
500 }
501 return $this->dataHandler;
502 }
503
504 /**
505 * @return \TYPO3\CMS\Workspaces\Service\WorkspaceService
506 */
507 protected function getWorkspaceService()
508 {
509 return GeneralUtility::makeInstance(
510 \TYPO3\CMS\Workspaces\Service\WorkspaceService::class
511 );
512 }
513
514 /**
515 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
516 */
517 protected function getBackendUser()
518 {
519 return $GLOBALS['BE_USER'];
520 }
521 }