TcaInline   C
last analyzed

Complexity

Total Complexity 57

Size/Duplication

Total Lines 478
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 57
eloc 215
c 1
b 0
f 0
dl 0
loc 478
rs 5.04

14 Methods

Rating   Name   Duplication   Size   Complexity  
B resolveRelatedRecordsOverlays() 0 79 9
A addData() 0 19 5
B addInlineFirstPid() 0 29 7
A isInlineField() 0 3 2
A isUserAllowedToModify() 0 3 1
A getLanguageService() 0 3 1
A getLiveDefaultId() 0 7 2
A addForeignSelectorAndUniquePossibleRecords() 0 42 3
A resolveRelatedRecords() 0 28 5
A getBackendUser() 0 3 1
A getWorkspacedUids() 0 20 6
A compileChildChild() 0 27 1
A resolveConnectedRecordUids() 0 24 6
B compileChild() 0 64 8

How to fix   Complexity   

Complex Class

Complex classes like TcaInline often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TcaInline, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Backend\Form\FormDataProvider;
17
18
use TYPO3\CMS\Backend\Form\Exception\DatabaseRecordException;
19
use TYPO3\CMS\Backend\Form\FormDataCompiler;
20
use TYPO3\CMS\Backend\Form\FormDataGroup\OnTheFly;
21
use TYPO3\CMS\Backend\Form\FormDataGroup\TcaDatabaseRecord;
22
use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
23
use TYPO3\CMS\Backend\Form\InlineStackProcessor;
24
use TYPO3\CMS\Backend\Utility\BackendUtility;
25
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
26
use TYPO3\CMS\Core\Database\RelationHandler;
27
use TYPO3\CMS\Core\Localization\LanguageService;
28
use TYPO3\CMS\Core\Messaging\FlashMessage;
29
use TYPO3\CMS\Core\Messaging\FlashMessageService;
30
use TYPO3\CMS\Core\Utility\GeneralUtility;
31
use TYPO3\CMS\Core\Utility\MathUtility;
32
use TYPO3\CMS\Core\Versioning\VersionState;
33
34
/**
35
 * Resolve and prepare inline data.
36
 */
37
class TcaInline extends AbstractDatabaseRecordProvider implements FormDataProviderInterface
38
{
39
    /**
40
     * Resolve inline fields
41
     *
42
     * @param array $result
43
     * @return array
44
     */
45
    public function addData(array $result)
46
    {
47
        $result = $this->addInlineFirstPid($result);
48
49
        foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
50
            if (!$this->isInlineField($fieldConfig)) {
51
                continue;
52
            }
53
            $result['processedTca']['columns'][$fieldName]['children'] = [];
54
            if (!$this->isUserAllowedToModify($fieldConfig)) {
55
                continue;
56
            }
57
            if ($result['inlineResolveExistingChildren']) {
58
                $result = $this->resolveRelatedRecords($result, $fieldName);
59
                $result = $this->addForeignSelectorAndUniquePossibleRecords($result, $fieldName);
60
            }
61
        }
62
63
        return $result;
64
    }
65
66
    /**
67
     * Is column of type "inline"
68
     *
69
     * @param array $fieldConfig
70
     * @return bool
71
     */
72
    protected function isInlineField($fieldConfig)
73
    {
74
        return !empty($fieldConfig['config']['type']) && $fieldConfig['config']['type'] === 'inline';
75
    }
76
77
    /**
78
     * Is user allowed to modify child elements
79
     *
80
     * @param array $fieldConfig
81
     * @return bool
82
     */
83
    protected function isUserAllowedToModify($fieldConfig)
84
    {
85
        return $this->getBackendUser()->check('tables_modify', $fieldConfig['config']['foreign_table']);
86
    }
87
88
    /**
89
     * The "entry" pid for inline records. Nested inline records can potentially hang around on different
90
     * pid's, but the entry pid is needed for AJAX calls, so that they would know where the action takes place on the page structure.
91
     *
92
     * @param array $result Incoming result
93
     * @return array Modified result
94
     * @todo: Find out when and if this is different from 'effectivePid'
95
     */
96
    protected function addInlineFirstPid(array $result)
97
    {
98
        if ($result['inlineFirstPid'] === null) {
99
            $table = $result['tableName'];
100
            $row = $result['databaseRow'];
101
            // If the parent is a page, use the uid(!) of the (new?) page as pid for the child records:
102
            if ($table === 'pages') {
103
                $liveVersionId = BackendUtility::getLiveVersionIdOfRecord('pages', $row['uid']);
104
                $pid = $liveVersionId ?? $row['uid'];
105
            } elseif (($row['pid'] ?? 0) < 0) {
106
                $prevRec = BackendUtility::getRecord($table, (int)abs($row['pid']));
107
                $pid = $prevRec['pid'];
108
            } else {
109
                $pid = $row['pid'] ?? 0;
110
            }
111
            if (MathUtility::canBeInterpretedAsInteger($pid)) {
112
                $pageRecord = BackendUtility::getRecord('pages', (int)$pid);
113
                if (($pageRecord[$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'] ?? null] ?? 0) > 0) {
114
                    $pid = (int)$pageRecord[$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']];
115
                }
116
            } elseif (strpos($pid, 'NEW') !== 0) {
117
                throw new \RuntimeException(
118
                    'inlineFirstPid should either be an integer or a "NEW..." string',
119
                    1521220142
120
                );
121
            }
122
            $result['inlineFirstPid'] = $pid;
123
        }
124
        return $result;
125
    }
126
127
    /**
128
     * Substitute the value in databaseRow of this inline field with an array
129
     * that contains the databaseRows of currently connected records and some meta information.
130
     *
131
     * @param array $result Result array
132
     * @param string $fieldName Current handle field name
133
     * @return array Modified item array
134
     */
135
    protected function resolveRelatedRecordsOverlays(array $result, $fieldName)
136
    {
137
        $childTableName = $result['processedTca']['columns'][$fieldName]['config']['foreign_table'];
138
139
        $connectedUidsOfLocalizedOverlay = [];
140
        if ($result['command'] === 'edit') {
141
            $connectedUidsOfLocalizedOverlay = $this->resolveConnectedRecordUids(
142
                $result['processedTca']['columns'][$fieldName]['config'],
143
                $result['tableName'],
144
                $result['databaseRow']['uid'],
145
                $result['databaseRow'][$fieldName]
146
            );
147
        }
148
        $result['databaseRow'][$fieldName] = implode(',', $connectedUidsOfLocalizedOverlay);
149
        $connectedUidsOfLocalizedOverlay = $this->getWorkspacedUids($connectedUidsOfLocalizedOverlay, $childTableName);
150
        if ($result['inlineCompileExistingChildren']) {
151
            $tableNameWithDefaultRecords = $result['tableName'];
152
            $connectedUidsOfDefaultLanguageRecord = $this->resolveConnectedRecordUids(
153
                $result['processedTca']['columns'][$fieldName]['config'],
154
                $tableNameWithDefaultRecords,
155
                $result['defaultLanguageRow']['uid'],
156
                $result['defaultLanguageRow'][$fieldName]
157
            );
158
            $connectedUidsOfDefaultLanguageRecord = $this->getWorkspacedUids($connectedUidsOfDefaultLanguageRecord, $childTableName);
159
160
            $showPossible = $result['processedTca']['columns'][$fieldName]['config']['appearance']['showPossibleLocalizationRecords'];
161
162
            // Find which records are localized, which records are not localized and which are
163
            // localized but miss default language record
164
            $fieldNameWithDefaultLanguageUid = $GLOBALS['TCA'][$childTableName]['ctrl']['transOrigPointerField'];
165
            foreach ($connectedUidsOfLocalizedOverlay as $localizedUid) {
166
                try {
167
                    $localizedRecord = $this->getRecordFromDatabase($childTableName, $localizedUid);
168
                } catch (DatabaseRecordException $e) {
169
                    // The child could not be compiled, probably it was deleted and a dangling mm record exists
170
                    $this->logger->warning(
0 ignored issues
show
Bug introduced by
The method warning() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

170
                    $this->logger->/** @scrutinizer ignore-call */ 
171
                                   warning(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
171
                        $e->getMessage(),
172
                        [
173
                            'table' => $childTableName,
174
                            'uid' => $localizedUid,
175
                            'exception' => $e
176
                        ]
177
                    );
178
                    continue;
179
                }
180
                $uidOfDefaultLanguageRecord = $localizedRecord[$fieldNameWithDefaultLanguageUid];
181
                if (in_array($uidOfDefaultLanguageRecord, $connectedUidsOfDefaultLanguageRecord)) {
182
                    // This localized child has a default language record. Remove this record from list of default language records
183
                    $connectedUidsOfDefaultLanguageRecord = array_diff($connectedUidsOfDefaultLanguageRecord, [$uidOfDefaultLanguageRecord]);
184
                }
185
                // Compile localized record
186
                $compiledChild = $this->compileChild($result, $fieldName, $localizedUid);
187
                $result['processedTca']['columns'][$fieldName]['children'][] = $compiledChild;
188
            }
189
            if ($showPossible) {
190
                foreach ($connectedUidsOfDefaultLanguageRecord as $defaultLanguageUid) {
191
                    // If there are still uids in $connectedUidsOfDefaultLanguageRecord, these are records that
192
                    // exist in default language, but are not localized yet. Compile and mark those
193
                    try {
194
                        $compiledChild = $this->compileChild($result, $fieldName, $defaultLanguageUid);
195
                    } catch (DatabaseRecordException $e) {
196
                        // The child could not be compiled, probably it was deleted and a dangling mm record exists
197
                        $this->logger->warning(
198
                            $e->getMessage(),
199
                            [
200
                                'table' => $childTableName,
201
                                'uid' => $defaultLanguageUid,
202
                                'exception' => $e
203
                            ]
204
                        );
205
                        continue;
206
                    }
207
                    $compiledChild['isInlineDefaultLanguageRecordInLocalizedParentContext'] = true;
208
                    $result['processedTca']['columns'][$fieldName]['children'][] = $compiledChild;
209
                }
210
            }
211
        }
212
213
        return $result;
214
    }
215
216
    /**
217
     * Substitute the value in databaseRow of this inline field with an array
218
     * that contains the databaseRows of currently connected records and some meta information.
219
     *
220
     * @param array $result Result array
221
     * @param string $fieldName Current handle field name
222
     * @return array Modified item array
223
     */
224
    protected function resolveRelatedRecords(array $result, $fieldName)
225
    {
226
        if ($result['defaultLanguageRow'] !== null) {
227
            return $this->resolveRelatedRecordsOverlays($result, $fieldName);
228
        }
229
230
        $childTableName = $result['processedTca']['columns'][$fieldName]['config']['foreign_table'];
231
        $connectedUidsOfDefaultLanguageRecord = $this->resolveConnectedRecordUids(
232
            $result['processedTca']['columns'][$fieldName]['config'],
233
            $result['tableName'],
234
            $result['databaseRow']['uid'],
235
            $result['databaseRow'][$fieldName]
236
        );
237
        $result['databaseRow'][$fieldName] = implode(',', $connectedUidsOfDefaultLanguageRecord);
238
239
        $connectedUidsOfDefaultLanguageRecord = $this->getWorkspacedUids($connectedUidsOfDefaultLanguageRecord, $childTableName);
240
241
        if ($result['inlineCompileExistingChildren']) {
242
            foreach ($connectedUidsOfDefaultLanguageRecord as $uid) {
243
                try {
244
                    $compiledChild = $this->compileChild($result, $fieldName, $uid);
245
                    $result['processedTca']['columns'][$fieldName]['children'][] = $compiledChild;
246
                } catch (DatabaseRecordException $e) {
247
                    // Nothing to do here, missing child is just not being rendered.
248
                }
249
            }
250
        }
251
        return $result;
252
    }
253
254
    /**
255
     * If there is a foreign_selector or foreign_unique configuration, fetch
256
     * the list of possible records that can be connected and attach the to the
257
     * inline configuration.
258
     *
259
     * @param array $result Result array
260
     * @param string $fieldName Current handle field name
261
     * @return array Modified item array
262
     */
263
    protected function addForeignSelectorAndUniquePossibleRecords(array $result, $fieldName)
264
    {
265
        if (!is_array($result['processedTca']['columns'][$fieldName]['config']['selectorOrUniqueConfiguration'] ?? null)) {
266
            return $result;
267
        }
268
269
        $selectorOrUniqueConfiguration = $result['processedTca']['columns'][$fieldName]['config']['selectorOrUniqueConfiguration'];
270
        $foreignFieldName = $selectorOrUniqueConfiguration['fieldName'];
271
        $selectorOrUniquePossibleRecords = [];
272
273
        if ($selectorOrUniqueConfiguration['config']['type'] === 'select') {
274
            // Compile child table data for this field only
275
            $selectDataInput = [
276
                'tableName' => $result['processedTca']['columns'][$fieldName]['config']['foreign_table'],
277
                'command' => 'new',
278
                // Since there is no existing record that may have a type, it does not make sense to
279
                // do extra handling of pageTsConfig merged here. Just provide "parent" pageTS as is
280
                'pageTsConfig' => $result['pageTsConfig'],
281
                'userTsConfig' => $result['userTsConfig'],
282
                'databaseRow' => $result['databaseRow'],
283
                'processedTca' => [
284
                    'ctrl' => [],
285
                    'columns' => [
286
                        $foreignFieldName => [
287
                            'config' => $selectorOrUniqueConfiguration['config'],
288
                        ],
289
                    ],
290
                ],
291
                'inlineExpandCollapseStateArray' => $result['inlineExpandCollapseStateArray'],
292
            ];
293
            /** @var OnTheFly $formDataGroup */
294
            $formDataGroup = GeneralUtility::makeInstance(OnTheFly::class);
295
            $formDataGroup->setProviderList([TcaSelectItems::class]);
296
            /** @var FormDataCompiler $formDataCompiler */
297
            $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
298
            $compilerResult = $formDataCompiler->compile($selectDataInput);
299
            $selectorOrUniquePossibleRecords = $compilerResult['processedTca']['columns'][$foreignFieldName]['config']['items'];
300
        }
301
302
        $result['processedTca']['columns'][$fieldName]['config']['selectorOrUniquePossibleRecords'] = $selectorOrUniquePossibleRecords;
303
304
        return $result;
305
    }
306
307
    /**
308
     * Compile a full child record
309
     *
310
     * @param array $result Result array of parent
311
     * @param string $parentFieldName Name of parent field
312
     * @param int $childUid Uid of child to compile
313
     * @return array Full result array
314
     */
315
    protected function compileChild(array $result, $parentFieldName, $childUid)
316
    {
317
        $parentConfig = $result['processedTca']['columns'][$parentFieldName]['config'];
318
        $childTableName = $parentConfig['foreign_table'];
319
320
        /** @var InlineStackProcessor $inlineStackProcessor */
321
        $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
322
        $inlineStackProcessor->initializeByGivenStructure($result['inlineStructure']);
323
        $inlineTopMostParent = $inlineStackProcessor->getStructureLevel(0) ?: [];
324
325
        /** @var TcaDatabaseRecord $formDataGroup */
326
        $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
327
        /** @var FormDataCompiler $formDataCompiler */
328
        $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
329
        $formDataCompilerInput = [
330
            'command' => 'edit',
331
            'tableName' => $childTableName,
332
            'vanillaUid' => (int)$childUid,
333
            // Give incoming returnUrl down to children so they generate a returnUrl back to
334
            // the originally opening record, also see "originalReturnUrl" in inline container
335
            // and FormInlineAjaxController
336
            'returnUrl' => $result['returnUrl'],
337
            'isInlineChild' => true,
338
            'inlineStructure' => $result['inlineStructure'],
339
            'inlineExpandCollapseStateArray' => $result['inlineExpandCollapseStateArray'],
340
            'inlineFirstPid' => $result['inlineFirstPid'],
341
            'inlineParentConfig' => $parentConfig,
342
343
            // values of the current parent element
344
            // it is always a string either an id or new...
345
            'inlineParentUid' => $result['databaseRow']['uid'],
346
            'inlineParentTableName' => $result['tableName'],
347
            'inlineParentFieldName' => $parentFieldName,
348
349
            // values of the top most parent element set on first level and not overridden on following levels
350
            'inlineTopMostParentUid' => $result['inlineTopMostParentUid'] ?: $inlineTopMostParent['uid'] ?? '',
351
            'inlineTopMostParentTableName' => $result['inlineTopMostParentTableName'] ?: $inlineTopMostParent['table'] ?? '',
352
            'inlineTopMostParentFieldName' => $result['inlineTopMostParentFieldName'] ?: $inlineTopMostParent['field'] ?? '',
353
        ];
354
355
        // For foreign_selector with useCombination $mainChild is the mm record
356
        // and $combinationChild is the child-child. For 1:n "normal" relations,
357
        // $mainChild is just the normal child record and $combinationChild is empty.
358
        $mainChild = $formDataCompiler->compile($formDataCompilerInput);
359
        if (($parentConfig['foreign_selector'] ?? false) && ($parentConfig['appearance']['useCombination'] ?? false)) {
360
            try {
361
                $mainChild['combinationChild'] = $this->compileChildChild($mainChild, $parentConfig);
362
            } catch (DatabaseRecordException $e) {
363
                // The child could not be compiled, probably it was deleted and a dangling mm record
364
                // exists. This is a data inconsistency, we catch this exception and create a flash message
365
                $message = vsprintf(
366
                    $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang.xlf:formEngine.databaseRecordErrorInlineChildChild'),
367
                    [$e->getTableName(), $e->getUid(), $childTableName, (int)$childUid]
368
                );
369
                $flashMessage = GeneralUtility::makeInstance(
370
                    FlashMessage::class,
371
                    $message,
372
                    '',
373
                    FlashMessage::ERROR
374
                );
375
                GeneralUtility::makeInstance(FlashMessageService::class)->getMessageQueueByIdentifier()->enqueue($flashMessage);
376
            }
377
        }
378
        return $mainChild;
379
    }
380
381
    /**
382
     * With useCombination set, not only content of the intermediate table, but also
383
     * the connected child should be rendered in one go. Prepare this here.
384
     *
385
     * @param array $child Full data array of "mm" record
386
     * @param array $parentConfig TCA configuration of "parent"
387
     * @return array Full data array of child
388
     */
389
    protected function compileChildChild(array $child, array $parentConfig)
390
    {
391
        // foreign_selector on intermediate is probably type=select, so data provider of this table resolved that to the uid already
392
        $childChildUid = $child['databaseRow'][$parentConfig['foreign_selector']][0];
393
        // child-child table name is set in child tca "the selector field" foreign_table
394
        $childChildTableName = $child['processedTca']['columns'][$parentConfig['foreign_selector']]['config']['foreign_table'];
395
        /** @var TcaDatabaseRecord $formDataGroup */
396
        $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
397
        /** @var FormDataCompiler $formDataCompiler */
398
        $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
399
400
        $formDataCompilerInput = [
401
            'command' => 'edit',
402
            'tableName' => $childChildTableName,
403
            'vanillaUid' => (int)$childChildUid,
404
            'isInlineChild' => true,
405
            'isInlineChildExpanded' => $child['isInlineChildExpanded'],
406
            // @todo: this is the wrong inline structure, isn't it? Shouldn't it contain the part from child child, too?
407
            'inlineStructure' => $child['inlineStructure'],
408
            'inlineFirstPid' => $child['inlineFirstPid'],
409
            // values of the top most parent element set on first level and not overridden on following levels
410
            'inlineTopMostParentUid' => $child['inlineTopMostParentUid'],
411
            'inlineTopMostParentTableName' => $child['inlineTopMostParentTableName'],
412
            'inlineTopMostParentFieldName' => $child['inlineTopMostParentFieldName'],
413
        ];
414
        $childChild = $formDataCompiler->compile($formDataCompilerInput);
415
        return $childChild;
416
    }
417
418
    /**
419
     * Substitute given list of uids in child table with workspace uid if needed
420
     *
421
     * @param array $connectedUids List of connected uids
422
     * @param string $childTableName Name of child table
423
     * @return array List of uids in workspace
424
     */
425
    protected function getWorkspacedUids(array $connectedUids, $childTableName)
426
    {
427
        $backendUser = $this->getBackendUser();
428
        $newConnectedUids = [];
429
        foreach ($connectedUids as $uid) {
430
            // Fetch workspace version of a record (if any):
431
            // @todo: Needs handling
432
            if ($backendUser->workspace !== 0 && BackendUtility::isTableWorkspaceEnabled($childTableName)) {
433
                $workspaceVersion = BackendUtility::getWorkspaceVersionOfRecord($backendUser->workspace, $childTableName, $uid, 'uid,t3ver_state');
434
                if (!empty($workspaceVersion)) {
435
                    $versionState = VersionState::cast($workspaceVersion['t3ver_state']);
436
                    if ($versionState->equals(VersionState::DELETE_PLACEHOLDER)) {
437
                        continue;
438
                    }
439
                    $uid = $workspaceVersion['uid'];
440
                }
441
            }
442
            $newConnectedUids[] = $uid;
443
        }
444
        return $newConnectedUids;
445
    }
446
447
    /**
448
     * Use RelationHandler to resolve connected uids.
449
     *
450
     * @param array $parentConfig TCA config section of parent
451
     * @param string $parentTableName Name of parent table
452
     * @param int $parentUid Uid of parent record
453
     * @param string $parentFieldValue Database value of parent record of this inline field
454
     * @return array Array with connected uids
455
     * @todo: Cover with unit tests
456
     */
457
    protected function resolveConnectedRecordUids(array $parentConfig, $parentTableName, $parentUid, $parentFieldValue)
458
    {
459
        $directlyConnectedIds = GeneralUtility::trimExplode(',', $parentFieldValue);
460
        if (empty($parentConfig['MM'])) {
461
            $parentUid = $this->getLiveDefaultId($parentTableName, $parentUid);
462
        }
463
        /** @var RelationHandler $relationHandler */
464
        $relationHandler = GeneralUtility::makeInstance(RelationHandler::class);
465
        $relationHandler->registerNonTableValues = (bool)($parentConfig['allowedIdValues'] ?? false);
466
        $relationHandler->start($parentFieldValue, $parentConfig['foreign_table'] ?? '', $parentConfig['MM'] ?? '', $parentUid, $parentTableName, $parentConfig);
467
        $foreignRecordUids = $relationHandler->getValueArray();
468
        $resolvedForeignRecordUids = [];
469
        foreach ($foreignRecordUids as $aForeignRecordUid) {
470
            if ($parentConfig['MM'] ?? $parentConfig['foreign_field'] ?? false) {
471
                $resolvedForeignRecordUids[] = (int)$aForeignRecordUid;
472
            } else {
473
                foreach ($directlyConnectedIds as $id) {
474
                    if ((int)$aForeignRecordUid === (int)$id) {
475
                        $resolvedForeignRecordUids[] = (int)$aForeignRecordUid;
476
                    }
477
                }
478
            }
479
        }
480
        return $resolvedForeignRecordUids;
481
    }
482
483
    /**
484
     * Gets the record uid of the live default record. If already
485
     * pointing to the live record, the submitted record uid is returned.
486
     *
487
     * @param string $tableName
488
     * @param int $uid
489
     * @return int
490
     * @todo: the workspace mess still must be resolved somehow
491
     */
492
    protected function getLiveDefaultId($tableName, $uid)
493
    {
494
        $liveDefaultId = BackendUtility::getLiveVersionIdOfRecord($tableName, $uid);
495
        if ($liveDefaultId === null) {
496
            $liveDefaultId = $uid;
497
        }
498
        return $liveDefaultId;
499
    }
500
501
    /**
502
     * @return BackendUserAuthentication
503
     */
504
    protected function getBackendUser()
505
    {
506
        return $GLOBALS['BE_USER'];
507
    }
508
509
    /**
510
     * @return LanguageService
511
     */
512
    protected function getLanguageService()
513
    {
514
        return $GLOBALS['LANG'];
515
    }
516
}
517