• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FluidTYPO3 / flux / 14774311267

01 May 2025 11:00AM UTC coverage: 93.246% (+0.3%) from 92.9%
14774311267

push

github

NamelessCoder
[TER] 11.0.0

7083 of 7596 relevant lines covered (93.25%)

66.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.75
/Classes/Provider/PageProvider.php
1
<?php
2
declare(strict_types=1);
3
namespace FluidTYPO3\Flux\Provider;
4

5
/*
6
 * This file is part of the FluidTYPO3/Flux project under GPLv2 or later.
7
 *
8
 * For the full copyright and license information, please read the
9
 * LICENSE.md file that was distributed with this source code.
10
 */
11

12
use FluidTYPO3\Flux\Builder\ViewBuilder;
13
use FluidTYPO3\Flux\Enum\ExtensionOption;
14
use FluidTYPO3\Flux\Enum\FormOption;
15
use FluidTYPO3\Flux\Form;
16
use FluidTYPO3\Flux\Form\Transformation\FormDataTransformer;
17
use FluidTYPO3\Flux\Service\CacheService;
18
use FluidTYPO3\Flux\Service\PageService;
19
use FluidTYPO3\Flux\Service\TypoScriptService;
20
use FluidTYPO3\Flux\Service\WorkspacesAwareRecordService;
21
use FluidTYPO3\Flux\Utility\ExtensionConfigurationUtility;
22
use FluidTYPO3\Flux\Utility\ExtensionNamingUtility;
23
use FluidTYPO3\Flux\Utility\MiscellaneousUtility;
24
use FluidTYPO3\Flux\Utility\RecursiveArrayUtility;
25
use TYPO3\CMS\Core\DataHandling\DataHandler;
26
use TYPO3\CMS\Core\Utility\GeneralUtility;
27
use TYPO3\CMS\Core\Utility\RootlineUtility;
28
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
29

30
/**
31
 * Page Configuration Provider
32
 *
33
 * Main Provider - triggers only on
34
 * records which have a selected action.
35
 * All other page records will be associated
36
 * with the SubPageProvider instead.
37
 */
38
class PageProvider extends AbstractProvider implements ProviderInterface
39
{
40
    const FIELD_NAME_MAIN = 'tx_fed_page_flexform';
41
    const FIELD_NAME_SUB = 'tx_fed_page_flexform_sub';
42
    const FIELD_ACTION_MAIN = 'tx_fed_page_controller_action';
43
    const FIELD_ACTION_SUB = 'tx_fed_page_controller_action_sub';
44

45
    protected ?string $tableName = 'pages';
46
    protected ?string $parentFieldName = 'pid';
47
    protected ?string $fieldName = self::FIELD_NAME_MAIN;
48
    protected string $extensionKey = 'FluidTYPO3.Flux';
49
    protected ?string $controllerName = 'Page';
50
    protected ?string $configurationSectionName = 'Configuration';
51
    protected ?string $pluginName = 'Page';
52

53
    private static array $cache = [];
54

55
    protected PageService $pageService;
56

57
    public function __construct(
58
        FormDataTransformer $formDataTransformer,
59
        WorkspacesAwareRecordService $recordService,
60
        ViewBuilder $viewBuilder,
61
        CacheService $cacheService,
62
        TypoScriptService $typoScriptService,
63
        PageService $pageService
64
    ) {
65
        parent::__construct($formDataTransformer, $recordService, $viewBuilder, $cacheService, $typoScriptService);
203✔
66
        $this->pageService = $pageService;
203✔
67
    }
68

69
    /**
70
     * Returns TRUE that this Provider should trigger if:
71
     *
72
     * - table matches 'pages'
73
     * - field is NULL or matches self::FIELD_NAME
74
     * - a selection was made in the "template for this page" field
75
     */
76
    public function trigger(array $row, ?string $table, ?string $field, ?string $extensionKey = null): bool
77
    {
78
        $isRightTable = ($table === $this->tableName);
7✔
79
        $isRightField = in_array($field, [null, self::FIELD_NAME_MAIN, self::FIELD_NAME_SUB], true);
7✔
80
        return (true === $isRightTable && true === $isRightField);
7✔
81
    }
82

83
    public function getForm(array $row, ?string $forField = null): ?Form
84
    {
85
        if ($row['deleted'] ?? false) {
35✔
86
            return null;
14✔
87
        }
88

89
        // If field is main field and "this page" has no selection or field is sub field and "subpages" has no selection
90
        if (($forField === self::FIELD_NAME_MAIN && empty($row[self::FIELD_ACTION_MAIN]))
21✔
91
            || ($forField === self::FIELD_NAME_SUB && empty($row[self::FIELD_ACTION_SUB]))
21✔
92
        ) {
93
            // The page inherits page layout from parent(s). Read the root line for the first page that defines a value
94
            // in the sub-action field, then use that record and resolve the Form used in the sub-configuration field.
95
            // If the row is a new page, use the inherited form from the parent page.
96
            $pageUid = $row['uid'] ?? 0;
14✔
97
            $pageUidIsParent = false;
14✔
98
            if (is_string($pageUid) && substr($pageUid, 0, 3) === 'NEW') {
14✔
99
                $pageUid = $row['pid'] ?? 0;
7✔
100
                $pageUidIsParent = true;
7✔
101
            }
102

103
            $pageTemplateConfiguration = $this->pageService->getPageTemplateConfiguration(
14✔
104
                (integer) $pageUid,
14✔
105
                $pageUidIsParent
14✔
106
            );
14✔
107

108
            $form = parent::getForm($pageTemplateConfiguration['record_sub'] ?? $row, self::FIELD_NAME_SUB);
14✔
109
        } else {
110
            $form = parent::getForm($row, $forField);
7✔
111
        }
112

113
        return $form;
21✔
114
    }
115

116
    public function getExtensionKey(array $row, ?string $forField = null): string
117
    {
118
        $controllerExtensionKey = $this->getControllerExtensionKeyFromRecord($row, $forField);
14✔
119
        if (!empty($controllerExtensionKey)) {
14✔
120
            return ExtensionNamingUtility::getExtensionKey($controllerExtensionKey);
7✔
121
        }
122
        return $this->extensionKey;
7✔
123
    }
124

125
    public function getTemplatePathAndFilename(array $row, ?string $forField = null): ?string
126
    {
127
        $templatePathAndFilename = $this->templatePathAndFilename;
7✔
128
        $action = $this->getControllerActionFromRecord($row, $forField);
7✔
129
        if (!empty($action)) {
7✔
130
            $pathsOrExtensionKey = $this->templatePaths
7✔
131
                ?? ExtensionNamingUtility::getExtensionKey($this->getControllerExtensionKeyFromRecord($row, $forField));
7✔
132
            $templatePaths = $this->viewBuilder->buildTemplatePaths($pathsOrExtensionKey);
7✔
133
            $action = ucfirst($action);
7✔
134
            $templatePathAndFilename = $templatePaths->resolveTemplateFileForControllerAndActionAndFormat(
7✔
135
                $this->getControllerNameFromRecord($row),
7✔
136
                $action
7✔
137
            );
7✔
138
        }
139
        return $templatePathAndFilename;
7✔
140
    }
141

142
    public function getControllerExtensionKeyFromRecord(array $row, ?string $forField = null): string
143
    {
144
        $action = $this->getControllerActionReferenceFromRecord($row, $forField);
14✔
145
        $offset = strpos($action, '->');
14✔
146
        if ($offset !== false) {
14✔
147
            return substr($action, 0, $offset);
7✔
148
        }
149
        return $this->extensionKey;
7✔
150
    }
151

152
    public function getControllerActionFromRecord(array $row, ?string $forField = null): string
153
    {
154
        $action = $this->getControllerActionReferenceFromRecord($row, $forField);
35✔
155
        $parts = explode('->', $action);
35✔
156
        $controllerActionName = end($parts);
35✔
157
        if (empty($controllerActionName)) {
35✔
158
            return 'default';
7✔
159
        }
160
        $controllerActionName[0] = strtolower($controllerActionName[0]);
28✔
161
        return $controllerActionName;
28✔
162
    }
163

164
    public function getControllerActionReferenceFromRecord(array $row, ?string $forField = null): string
165
    {
166
        if (($forField === self::FIELD_NAME_MAIN || $forField === null) && !empty($row[self::FIELD_ACTION_MAIN])) {
28✔
167
            return is_array($row[self::FIELD_ACTION_MAIN])
14✔
168
                ? $row[self::FIELD_ACTION_MAIN][0]
×
169
                : $row[self::FIELD_ACTION_MAIN];
14✔
170
        } elseif ($forField === self::FIELD_NAME_SUB && !empty($row[self::FIELD_ACTION_SUB])) {
14✔
171
            return is_array($row[self::FIELD_ACTION_SUB])
7✔
172
                ? $row[self::FIELD_ACTION_SUB][0]
×
173
                : $row[self::FIELD_ACTION_SUB];
7✔
174
        }
175
        if (isset($row['uid'])) {
7✔
176
            $configuration = $this->pageService->getPageTemplateConfiguration((integer) $row['uid']);
×
177
            $fieldName = self::FIELD_ACTION_SUB;
×
178
            if ($forField === self::FIELD_NAME_MAIN) {
×
179
                $fieldName = self::FIELD_ACTION_MAIN;
×
180
            }
181
            return ($configuration[$fieldName] ?? 'flux->default') ?: 'flux->default';
×
182
        }
183
        return 'flux->default';
7✔
184
    }
185

186
    public function getFlexFormValues(array $row, ?string $forField = null): array
187
    {
188
        $immediateConfiguration = $this->getFlexFormValuesSingle($row);
14✔
189
        $inheritedConfiguration = $this->getInheritedConfiguration($row);
14✔
190
        return RecursiveArrayUtility::merge($inheritedConfiguration, $immediateConfiguration);
14✔
191
    }
192

193
    public function getFlexFormValuesSingle(array $row, ?string $forField = null): array
194
    {
195
        $fieldName = $forField ?? $this->getFieldName($row);
14✔
196
        $form = $this->getForm($row, $forField);
14✔
197
        $immediateConfiguration = $this->formDataTransformer->convertFlexFormContentToArray(
14✔
198
            $row[$fieldName] ?? '',
14✔
199
            $form,
14✔
200
            null,
14✔
201
            null
14✔
202
        );
14✔
203
        return $immediateConfiguration;
14✔
204
    }
205

206
    public function postProcessRecord(
207
        string $operation,
208
        int $id,
209
        array $row,
210
        DataHandler $reference,
211
        array $removals = []
212
    ): bool {
213
        if ($operation === 'update') {
7✔
214
            $stored = $this->recordService->getSingle((string) $this->getTableName($row), '*', $id);
7✔
215
            if (!$stored) {
7✔
216
                return false;
×
217
            }
218
            $before = $stored;
7✔
219
            $tableName = $this->getTableName($stored);
7✔
220

221
            $record = RecursiveArrayUtility::mergeRecursiveOverrule(
7✔
222
                $stored,
7✔
223
                $reference->datamap[$this->tableName][$id] ?? []
7✔
224
            );
7✔
225

226
            foreach ([self::FIELD_NAME_MAIN, self::FIELD_NAME_SUB] as $tableFieldName) {
7✔
227
                $form = $this->getForm($record, $tableFieldName);
7✔
228
                if (!$form) {
7✔
229
                    continue;
×
230
                }
231

232
                $removeForField = [];
7✔
233
                $protected = array_flip($this->extractFieldNamesToProtect($record, $tableFieldName));
7✔
234
                foreach ($form->getFields() as $field) {
7✔
235
                    /** @var Form\Container\Sheet $parent */
236
                    $parent = $field->getParent();
7✔
237
                    $fieldName = (string) $field->getName();
7✔
238
                    $sheetName = (string) $parent->getName();
7✔
239
                    $inherit = (boolean) $field->getInherit();
7✔
240
                    $inheritEmpty = (boolean) $field->getInheritEmpty();
7✔
241
                    if (is_array($record[$tableFieldName]['data'] ?? null)) {
7✔
242
                        $value = $record[$tableFieldName]['data'][$sheetName]['lDEF'][$fieldName]['vDEF'] ?? null;
7✔
243
                        $inheritedConfiguration = $this->getInheritedConfiguration($record);
7✔
244
                        if (!isset($inheritedConfiguration[$fieldName])) {
7✔
245
                            continue;
7✔
246
                        }
247
                        $inheritedValue = $this->getInheritedPropertyValueByDottedPath(
×
248
                            $inheritedConfiguration,
×
249
                            $fieldName
×
250
                        );
×
251
                        $empty = (true === empty($value) && $value !== '0' && $value !== 0);
×
252
                        $same = ($inheritedValue === $value);
×
253
                        $protected = (bool) ($protected[$fieldName] ?? false);
×
254
                        if (!$protected && ($same && $inherit || ($inheritEmpty && $empty))) {
×
255
                            $removeForField[] = $fieldName;
×
256
                        }
257
                    }
258
                }
259
                $removeForField = array_merge(
7✔
260
                    $removeForField,
7✔
261
                    $this->extractFieldNamesToClear($record, $tableFieldName)
7✔
262
                );
7✔
263
                $removeForField = array_unique($removeForField);
7✔
264

265
                if (!empty($stored[$tableFieldName])) {
7✔
266
                    $stored[$tableFieldName] = MiscellaneousUtility::cleanFlexFormXml(
7✔
267
                        $stored[$tableFieldName],
7✔
268
                        $removeForField
7✔
269
                    );
7✔
270
                }
271
            }
272

273
            if ($before !== $stored) {
7✔
274
                $this->recordService->update((string) $tableName, $stored);
7✔
275
            }
276
        }
277

278
        return false;
7✔
279
    }
280

281
    public function processTableConfiguration(array $row, array $configuration): array
282
    {
283
        $currentPageRecord = $this->recordService->getSingle(
21✔
284
            (string) $this->getTableName($row),
21✔
285
            'uid,' . self::FIELD_NAME_MAIN . ',' . self::FIELD_NAME_SUB,
21✔
286
            $configuration['vanillaUid']
21✔
287
        );
21✔
288
        if (!$currentPageRecord) {
21✔
289
            return $configuration;
7✔
290
        }
291

292
        $tree = array_reverse($this->getInheritanceTree($currentPageRecord), true);
14✔
293

294
        $inheritedConfiguration = [];
14✔
295

296
        if (!empty($currentPageRecord[self::FIELD_NAME_SUB])) {
14✔
297
            $currentPageRecord[self::FIELD_NAME_SUB] = $this->convertXmlToArray(
×
298
                $currentPageRecord[self::FIELD_NAME_SUB]
×
299
            ) ?? [];
×
300
        }
301
        /** @var Form&Form $form */
302
        $form = $this->getForm($row, self::FIELD_NAME_SUB);
14✔
303
        foreach ($tree as $branch) {
14✔
304
            if (!empty($branch[self::FIELD_NAME_SUB])) {
14✔
305
                $branchData = $this->convertXmlToArray($branch[self::FIELD_NAME_SUB] ?? '') ?? [];
14✔
306
                $inheritedConfiguration = RecursiveArrayUtility::mergeRecursiveOverrule(
14✔
307
                    $inheritedConfiguration,
14✔
308
                    $branchData
14✔
309
                );
14✔
310
            }
311
        }
312

313
        $inheritedConfigurationForFields = [];
14✔
314
        foreach ([self::FIELD_NAME_MAIN, self::FIELD_NAME_SUB] as $field) {
14✔
315
            $inheritedConfigurationForFields[$field] = $inheritedConfiguration;
14✔
316
            $dataMirror = ['data' => []];
14✔
317
            $this->extractDataStorageMirrorWithInheritableFields($form, $dataMirror['data']);
14✔
318
            $this->unsetUninheritableFieldsInInheritedConfiguration(
14✔
319
                $inheritedConfigurationForFields[$field],
14✔
320
                $currentPageRecord[self::FIELD_NAME_MAIN],
14✔
321
                $dataMirror
14✔
322
            );
14✔
323
        }
324

325
        if (!empty($configuration['databaseRow'][self::FIELD_NAME_MAIN])) {
14✔
326
            if (is_array($configuration['databaseRow'][self::FIELD_NAME_MAIN])) {
14✔
327
                $currentData = $configuration['databaseRow'][self::FIELD_NAME_MAIN];
7✔
328
            } else {
329
                $currentData = $this->convertXmlToArray($configuration['databaseRow'][self::FIELD_NAME_MAIN]) ?? [];
7✔
330
            }
331
            $configuration['databaseRow'][self::FIELD_NAME_MAIN] = RecursiveArrayUtility::mergeRecursiveOverrule(
14✔
332
                $inheritedConfigurationForFields[self::FIELD_NAME_MAIN],
14✔
333
                $currentData,
14✔
334
                false,
14✔
335
                true
14✔
336
            );
14✔
337
        }
338

339
        if (is_array($configuration['databaseRow'][self::FIELD_NAME_SUB])) {
14✔
340
            $subData = $configuration['databaseRow'][self::FIELD_NAME_SUB];
7✔
341
        } else {
342
            $subData = $this->convertXmlToArray($configuration['databaseRow'][self::FIELD_NAME_SUB]) ?? [];
7✔
343
        }
344

345
        $configuration['databaseRow'][self::FIELD_NAME_SUB] = RecursiveArrayUtility::mergeRecursiveOverrule(
14✔
346
            $inheritedConfigurationForFields[self::FIELD_NAME_SUB],
14✔
347
            $subData
14✔
348
        );
14✔
349

350
        return parent::processTableConfiguration($row, $configuration);
14✔
351
    }
352

353
    public function getPreview(array $row): array
354
    {
355
        $previewContent = $this->viewBuilder->buildPreviewView(
×
356
            $this->getControllerExtensionKeyFromRecord($row),
×
357
            $this->getControllerNameFromRecord($row),
×
358
            $this->getControllerActionFromRecord($row),
×
359
            $this->getPluginName() ?? $this->getControllerNameFromRecord($row),
×
360
            $this->getTemplatePathAndFilename($row)
×
361
        )->getPreview($this, $row, true);
×
362
        return [null, $previewContent, empty($previewContent)];
×
363
    }
364

365
    /**
366
     * @param array|string|null $immediateConfiguration
367
     */
368
    private function unsetUninheritableFieldsInInheritedConfiguration(
369
        array &$inheritedConfiguration,
370
        &$immediateConfiguration,
371
        array &$dataMirror
372
    ): void {
373
        foreach ($inheritedConfiguration as $key => &$value) {
14✔
374
            if (!is_array($value)) {
14✔
375
                continue;
14✔
376
            }
377

378
            $inheritedValueIsSection = $this->checkIsSection($inheritedConfiguration[$key] ?? []);
14✔
379
            if (!isset($dataMirror[$key]) && !$inheritedValueIsSection) {
14✔
380
                unset($inheritedConfiguration[$key]);
×
381
                continue;
×
382
            }
383
            $dataMirrorItem = &$dataMirror[$key];
14✔
384
            if ($dataMirrorItem instanceof Form\FieldInterface && !$dataMirrorItem->getInherit()) {
14✔
385
                unset($inheritedConfiguration[$key]);
×
386
                continue;
×
387
            }
388
            $immediateConfigurationIsArray = is_array($immediateConfiguration);
14✔
389
            $immediateSubConfiguration = $immediateConfigurationIsArray ? $immediateConfiguration[$key] ?? null : null;
14✔
390
            if ($immediateConfigurationIsArray
14✔
391
                && is_array($immediateSubConfiguration)
14✔
392
                && $inheritedValueIsSection
393
                && $this->checkIsSection($immediateConfiguration[$key])
14✔
394
            ) {
395
                // Immediate configuration is a section, and it has items. Do not allow inheritance.
396
                unset($inheritedConfiguration[$key]);
×
397
                continue;
×
398
            } elseif ($inheritedValueIsSection) {
14✔
399
                // Do not further process an inherited section - inheritance is desired.
400
                continue;
×
401
            }
402
            $this->unsetUninheritableFieldsInInheritedConfiguration(
14✔
403
                $inheritedConfiguration[$key],
14✔
404
                $immediateSubConfiguration,
14✔
405
                $dataMirrorItem,
14✔
406
            );
14✔
407
        }
408
    }
409

410
    private function checkIsSection(array $data): bool
411
    {
412
        // Determine if we are working on a section object. If so, the inherited configuration will contain an extra
413
        // dimension; an alpha-numeric unique key 22 chars in length. We can identify if that is the case by
414
        // checking that every array key is exactly 22 chars and every element contains a "_TOGGLE" key.
415
        $numberOfValues = count($data);
14✔
416
        return $numberOfValues > 0
14✔
417
            && strlen(implode('', array_keys($data))) === ($numberOfValues * 22)
14✔
418
            && count(array_column($data, '_TOGGLE')) === $numberOfValues;
14✔
419
    }
420

421
    private function extractDataStorageMirrorWithInheritableFields(
422
        Form\FieldContainerInterface $container,
423
        array &$parentArrayPosition
424
    ): void {
425
        if (!$container->getInherit()) {
14✔
426
            return;
×
427
        }
428
        foreach ($container->getChildren() as $child) {
14✔
429
            if (!$child->getInherit()) {
14✔
430
                continue;
×
431
            }
432
            $childName = $child->getName();
14✔
433
            if ($child instanceof Form\Container\Section) {
14✔
434
                foreach ($child->getChildren() as $sectionObject) {
×
435
                    /** @var Form\Container\SectionObject $sectionObject */
436
                    $sectionObjectName = $sectionObject->getName();
×
437
                    $parentArrayPosition['lDEF'][$childName]['el'][$sectionObjectName]['el'] = [];
×
438
                    $position = &$parentArrayPosition['lDEF'][$childName]['el'][$sectionObjectName]['el'];
×
439
                    foreach ($sectionObject->getChildren() as $field) {
×
440
                        $position[$field->getName()] = $field;
×
441
                    }
442
                }
443
            } elseif (!$child instanceof Form\FieldContainerInterface) {
14✔
444
                $parentArrayPosition['lDEF'][$childName]['vDEF'] = $child;
×
445
            } else {
446
                $parentArrayPosition[$childName] = [];
14✔
447
                $this->extractDataStorageMirrorWithInheritableFields($child, $parentArrayPosition[$childName]);
14✔
448
            }
449
        }
450
    }
451

452
    /**
453
     * @codeCoverageIgnore
454
     */
455
    protected function convertXmlToArray(string $xml): ?array
456
    {
457
        /** @var string|array $converted */
458
        $converted = GeneralUtility::xml2array($xml);
459
        return is_string($converted) ? null : $converted;
460
    }
461

462
    /**
463
     * Gets an inheritance tree (ordered first parent -> ... -> root record)
464
     * of record arrays containing raw values, stopping at the first parent
465
     * record that defines a page layout to use in "page layout - subpages".
466
     */
467
    protected function getInheritanceTree(array $row): array
468
    {
469
        $previousTemplate = $row[self::FIELD_ACTION_MAIN] ?? null;
28✔
470
        $configuredInheritance = ExtensionConfigurationUtility::getOption(ExtensionOption::OPTION_INHERITANCE_MODE);
28✔
471

472
        $form = $this->getForm($row);
28✔
473

474
        $defaultInheritanceMode = ($form ? $form->getOption(FormOption::INHERITANCE_MODE) : $configuredInheritance)
28✔
475
            ?? $configuredInheritance;
22✔
476

477
        $records = $this->loadRecordTreeFromDatabase($row);
28✔
478
        foreach ($records as $index => $record) {
28✔
479
            $childForm = $this->getForm($record);
21✔
480
            $subAction = $record[self::FIELD_ACTION_SUB] ?? null;
21✔
481
            $hasSubAction = !empty($subAction);
21✔
482

483
            if ($childForm) {
21✔
484
                $inheritanceMode = $childForm->getOption(FormOption::INHERITANCE_MODE) ?? $defaultInheritanceMode;
14✔
485
            } else {
486
                $inheritanceMode = $defaultInheritanceMode;
14✔
487
            }
488

489
            if ($inheritanceMode === 'restricted'
21✔
490
                && $hasSubAction
491
                && ($subAction ?? $previousTemplate) !== $previousTemplate
21✔
492
            ) {
493
                return array_slice($records, 0, $index + 1);
14✔
494
            }
495
            $previousTemplate = $subAction ?? $previousTemplate;
21✔
496
        }
497
        return $records;
14✔
498
    }
499

500
    protected function getInheritedConfiguration(array $row): array
501
    {
502
        $tableName = $this->getTableName($row);
42✔
503
        $tableFieldName = $this->getFieldName($row);
42✔
504
        $uid = $row['uid'] ?? '';
42✔
505
        $cacheKey = $tableName . $tableFieldName . $uid;
42✔
506
        if (false === isset(self::$cache[$cacheKey])) {
42✔
507
            $tree = array_reverse($this->getInheritanceTree($row), true);
35✔
508
            $data = [];
35✔
509
            foreach ($tree as $branch) {
35✔
510
                $values = $this->getFlexFormValuesSingle($branch, self::FIELD_NAME_SUB);
35✔
511
                $data = RecursiveArrayUtility::mergeRecursiveOverrule($data, $values, false, true);
35✔
512
            }
513
            self::$cache[$cacheKey] = $data;
35✔
514
        }
515
        return self::$cache[$cacheKey];
42✔
516
    }
517

518
    /**
519
     * @return mixed
520
     */
521
    protected function getInheritedPropertyValueByDottedPath(array $inheritedConfiguration, string $propertyPath)
522
    {
523
        if (true === empty($propertyPath)) {
35✔
524
            return null;
7✔
525
        } elseif (false === strpos($propertyPath, '.')) {
28✔
526
            if (isset($inheritedConfiguration[$propertyPath])) {
14✔
527
                return ObjectAccess::getProperty($inheritedConfiguration, $propertyPath);
7✔
528
            }
529
            return null;
7✔
530
        }
531
        return ObjectAccess::getPropertyPath($inheritedConfiguration, $propertyPath);
14✔
532
    }
533

534
    protected function unsetInheritedValues(Form\FormInterface $field, array $values): array
535
    {
536
        $name = $field->getName();
21✔
537
        $inherit = $field->getInherit();
21✔
538
        $inheritEmpty = $field->getInheritEmpty();
21✔
539
        $value = $values[$name] ?? null;
21✔
540
        $empty = empty($value) && !in_array($value, [0, '0'], true);
21✔
541
        if (!$inherit || ($inheritEmpty && $empty)) {
21✔
542
            unset($values[$name]);
7✔
543
        }
544
        return $values;
21✔
545
    }
546

547
    protected function loadRecordTreeFromDatabase(array $record): array
548
    {
549
        if (empty($record)) {
14✔
550
            return [];
7✔
551
        }
552
        /** @var RootlineUtility $rootLineUtility */
553
        $rootLineUtility = GeneralUtility::makeInstance(RootlineUtility::class, (integer) ($record['uid'] ?? 0));
7✔
554
        return array_slice($rootLineUtility->get(), 1);
7✔
555
    }
556
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc