Passed
Push — master ( fb6744...da9c6d )
by
unknown
17:04
created

SiteTcaInline::getBackendUser()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
18
namespace TYPO3\CMS\Backend\Form\FormDataProvider;
19
20
use TYPO3\CMS\Backend\Form\FormDataCompiler;
21
use TYPO3\CMS\Backend\Form\FormDataGroup\SiteConfigurationDataGroup;
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\Exception\SiteNotFoundException;
26
use TYPO3\CMS\Core\Site\SiteFinder;
27
use TYPO3\CMS\Core\Utility\GeneralUtility;
28
use TYPO3\CMS\Core\Utility\MathUtility;
29
30
/**
31
 * Special data provider for the sites configuration module.
32
 *
33
 * Handle inline children of 'site'
34
 */
35
class SiteTcaInline extends AbstractDatabaseRecordProvider implements FormDataProviderInterface
36
{
37
    /**
38
     * Resolve inline fields
39
     *
40
     * @param array $result
41
     * @return array
42
     */
43
    public function addData(array $result): array
44
    {
45
        $result = $this->addInlineFirstPid($result);
46
        foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
47
            if (!$this->isInlineField($fieldConfig)) {
48
                continue;
49
            }
50
            $childTableName = $fieldConfig['config']['foreign_table'] ?? '';
51
            if (!in_array($childTableName, ['site_errorhandling', 'site_route', 'site_base_variant'], true)) {
52
                throw new \RuntimeException('Inline relation to other tables not implemented', 1522494737);
53
            }
54
            $result['processedTca']['columns'][$fieldName]['children'] = [];
55
            $result = $this->resolveSiteRelatedChildren($result, $fieldName);
56
            if (!empty($result['processedTca']['columns'][$fieldName]['config']['selectorOrUniqueConfiguration'])) {
57
                throw new \RuntimeException('selectorOrUniqueConfiguration not implemented in sites module', 1624313533);
58
            }
59
        }
60
61
        return $result;
62
    }
63
64
    /**
65
     * Is column of type "inline"
66
     *
67
     * @param array $fieldConfig
68
     * @return bool
69
     */
70
    protected function isInlineField(array $fieldConfig): bool
71
    {
72
        return !empty($fieldConfig['config']['type']) && $fieldConfig['config']['type'] === 'inline';
73
    }
74
75
    /**
76
     * The "entry" pid for inline records. Nested inline records can potentially hang around on different
77
     * 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.
78
     *
79
     * @param array $result Incoming result
80
     * @return array Modified result
81
     * @todo: Find out when and if this is different from 'effectivePid'
82
     */
83
    protected function addInlineFirstPid(array $result): array
84
    {
85
        if ($result['inlineFirstPid'] === null) {
86
            $table = $result['tableName'];
87
            $row = $result['databaseRow'];
88
            // If the parent is a page, use the uid(!) of the (new?) page as pid for the child records:
89
            if ($table === 'pages') {
90
                $liveVersionId = BackendUtility::getLiveVersionIdOfRecord('pages', $row['uid']);
91
                $pid = $liveVersionId ?? $row['uid'];
92
            } elseif (($row['pid'] ?? 0) < 0) {
93
                $prevRec = BackendUtility::getRecord($table, (int)abs($row['pid']));
94
                $pid = $prevRec['pid'];
95
            } else {
96
                $pid = $row['pid'] ?? 0;
97
            }
98
            if (MathUtility::canBeInterpretedAsInteger($pid)) {
99
                $pageRecord = BackendUtility::getRecord('pages', (int)$pid);
100
                if (($pageRecord[$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'] ?? null] ?? 0) > 0) {
101
                    $pid = (int)$pageRecord[$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField']];
102
                }
103
            } elseif (strpos($pid, 'NEW') !== 0) {
104
                throw new \RuntimeException(
105
                    'inlineFirstPid should either be an integer or a "NEW..." string',
106
                    1521220141
107
                );
108
            }
109
            $result['inlineFirstPid'] = $pid;
110
        }
111
        return $result;
112
    }
113
114
    /**
115
     * Substitute the value in databaseRow of this inline field with an array
116
     * that contains the databaseRows of currently connected records and some meta information.
117
     *
118
     * @param array $result Result array
119
     * @param string $fieldName Current handle field name
120
     * @return array Modified item array
121
     */
122
    protected function resolveSiteRelatedChildren(array $result, string $fieldName): array
123
    {
124
        $connectedUids = [];
125
        if ($result['command'] === 'edit') {
126
            $siteConfigurationForPageUid = (int)$result['databaseRow']['rootPageId'][0];
127
            $siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
128
            try {
129
                $site = $siteFinder->getSiteByRootPageId($siteConfigurationForPageUid);
130
            } catch (SiteNotFoundException $e) {
131
                $site = null;
132
            }
133
            $siteConfiguration = $site ? $site->getConfiguration() : [];
134
            if (is_array($siteConfiguration[$fieldName] ?? false)) {
135
                $connectedUids = array_keys($siteConfiguration[$fieldName]);
136
            }
137
        }
138
139
        $result['databaseRow'][$fieldName] = implode(',', $connectedUids);
140
        if ($result['inlineCompileExistingChildren']) {
141
            foreach ($connectedUids as $uid) {
142
                if (strpos((string)$uid, 'NEW') !== 0) {
143
                    $compiledChild = $this->compileChild($result, $fieldName, (int)$uid);
144
                    $result['processedTca']['columns'][$fieldName]['children'][] = $compiledChild;
145
                }
146
            }
147
        }
148
149
        return $result;
150
    }
151
152
    /**
153
     * Compile a full child record
154
     *
155
     * @param array $result Result array of parent
156
     * @param string $parentFieldName Name of parent field
157
     * @param int $childUid Uid of child to compile
158
     * @return array Full result array
159
     */
160
    protected function compileChild(array $result, string $parentFieldName, int $childUid): array
161
    {
162
        $parentConfig = $result['processedTca']['columns'][$parentFieldName]['config'];
163
        $childTableName = $parentConfig['foreign_table'];
164
165
        /** @var InlineStackProcessor $inlineStackProcessor */
166
        $inlineStackProcessor = GeneralUtility::makeInstance(InlineStackProcessor::class);
167
        $inlineStackProcessor->initializeByGivenStructure($result['inlineStructure']);
168
        $inlineTopMostParent = $inlineStackProcessor->getStructureLevel(0);
169
170
        $formDataGroup = GeneralUtility::makeInstance(SiteConfigurationDataGroup::class);
171
        $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
172
        $formDataCompilerInput = [
173
            'command' => 'edit',
174
            'tableName' => $childTableName,
175
            'vanillaUid' => $childUid,
176
            // Give incoming returnUrl down to children so they generate a returnUrl back to
177
            // the originally opening record, also see "originalReturnUrl" in inline container
178
            // and FormInlineAjaxController
179
            'returnUrl' => $result['returnUrl'],
180
            'isInlineChild' => true,
181
            'inlineStructure' => $result['inlineStructure'],
182
            'inlineExpandCollapseStateArray' => $result['inlineExpandCollapseStateArray'],
183
            'inlineFirstPid' => $result['inlineFirstPid'],
184
            'inlineParentConfig' => $parentConfig,
185
186
            // values of the current parent element
187
            // it is always a string either an id or new...
188
            'inlineParentUid' => $result['databaseRow']['uid'],
189
            'inlineParentTableName' => $result['tableName'],
190
            'inlineParentFieldName' => $parentFieldName,
191
192
            // values of the top most parent element set on first level and not overridden on following levels
193
            'inlineTopMostParentUid' => $result['inlineTopMostParentUid'] ?: ($inlineTopMostParent['uid'] ?? null),
194
            'inlineTopMostParentTableName' => $result['inlineTopMostParentTableName'] ?: ($inlineTopMostParent['table'] ?? ''),
195
            'inlineTopMostParentFieldName' => $result['inlineTopMostParentFieldName'] ?: ($inlineTopMostParent['field'] ?? ''),
196
        ];
197
198
        if (($parentConfig['foreign_selector'] ?? false) && ($parentConfig['appearance']['useCombination'] ?? false)) {
199
            throw new \RuntimeException('useCombination not implemented in sites module', 1522493097);
200
        }
201
        return $formDataCompiler->compile($formDataCompilerInput);
202
    }
203
}
204