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

FluidTYPO3 / flux / 18564197260

16 Oct 2025 02:11PM UTC coverage: 92.662% (-0.08%) from 92.743%
18564197260

push

github

NamelessCoder
[BUGFIX] Correct various lookup attempts to find current record

Fixes mainly a problem with Flux in an INT uncached context where
the resolved request and therefore content object data was not the
expected one (returned page row from inside a content context).

This fixes that problem by more consistently handing over the request
to the lookup methods and using the content object data when it is
availble in the content object.

3 of 10 new or added lines in 1 file covered. (30.0%)

12 existing lines in 2 files now uncovered.

7084 of 7645 relevant lines covered (92.66%)

65.87 hits per line

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

87.31
/Classes/Controller/AbstractFluxController.php
1
<?php
2
declare(strict_types=1);
3
namespace FluidTYPO3\Flux\Controller;
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\RenderingContextBuilder;
13
use FluidTYPO3\Flux\Builder\RequestBuilder;
14
use FluidTYPO3\Flux\Builder\ViewBuilder;
15
use FluidTYPO3\Flux\Hooks\HookHandler;
16
use FluidTYPO3\Flux\Integration\NormalizedData\DataAccessTrait;
17
use FluidTYPO3\Flux\Integration\Resolver;
18
use FluidTYPO3\Flux\Provider\Interfaces\ControllerProviderInterface;
19
use FluidTYPO3\Flux\Provider\Interfaces\DataStructureProviderInterface;
20
use FluidTYPO3\Flux\Provider\Interfaces\FluidProviderInterface;
21
use FluidTYPO3\Flux\Provider\ProviderResolver;
22
use FluidTYPO3\Flux\Service\TypoScriptService;
23
use FluidTYPO3\Flux\Service\WorkspacesAwareRecordService;
24
use FluidTYPO3\Flux\Utility\ContentObjectFetcher;
25
use FluidTYPO3\Flux\Utility\ExtensionNamingUtility;
26
use FluidTYPO3\Flux\Utility\RecursiveArrayUtility;
27
use FluidTYPO3\Flux\ViewHelpers\FormViewHelper;
28
use Psr\Http\Message\ResponseFactoryInterface;
29
use Psr\Http\Message\ServerRequestInterface;
30
use TYPO3\CMS\Core\Utility\GeneralUtility;
31
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
32
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
33
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
34
use TYPO3\CMS\Extbase\Mvc\Controller\Arguments;
35
use TYPO3\CMS\Extbase\Mvc\Controller\ControllerInterface;
36
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
37
use TYPO3\CMS\Extbase\Mvc\Request;
38
use TYPO3\CMS\Extbase\Mvc\Response;
39
use TYPO3\CMS\Extbase\Mvc\ResponseInterface;
40
use TYPO3\CMS\Fluid\View\TemplateView;
41
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
42
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
43
use TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperVariableContainer;
44
use TYPO3Fluid\Fluid\View\ViewInterface;
45

46
/**
47
 * Abstract Flux-enabled controller
48
 *
49
 * Extends a traditional ActionController with new services and methods
50
 * to ease interaction with Flux forms. Is not required as subclass for
51
 * Controllers rendering records associated with Flux - all it does is
52
 * ease the interaction by providing a common API.
53
 */
54
abstract class AbstractFluxController extends ActionController
55
{
56
    use DataAccessTrait;
57

58
    protected string $extensionName = 'FluidTYPO3.Flux';
59
    protected ?string $fluxRecordField = 'pi_flexform';
60
    protected ?string $fluxTableName = 'tt_content';
61
    protected array $data = [];
62
    private ?array $record = null;
63

64
    protected RenderingContextBuilder $renderingContextBuilder;
65
    protected RequestBuilder $requestBuilder;
66
    protected WorkspacesAwareRecordService $recordService;
67
    protected TypoScriptService $typoScriptService;
68
    protected ProviderResolver $providerResolver;
69
    protected Resolver $resolver;
70
    protected ViewBuilder $viewBuilder;
71
    protected ?ControllerProviderInterface $provider = null;
72

73
    public function __construct(
74
        RenderingContextBuilder $renderingContextBuilder,
75
        RequestBuilder $requestBuilder,
76
        WorkspacesAwareRecordService $recordService,
77
        TypoScriptService $typoScriptService,
78
        ProviderResolver $providerResolver,
79
        Resolver $resolver,
80
        ViewBuilder $viewBuilder
81
    ) {
82
        $this->renderingContextBuilder = $renderingContextBuilder;
154✔
83
        $this->requestBuilder = $requestBuilder;
154✔
84
        $this->recordService = $recordService;
154✔
85
        $this->typoScriptService = $typoScriptService;
154✔
86
        $this->providerResolver = $providerResolver;
154✔
87
        $this->resolver = $resolver;
154✔
88
        $this->viewBuilder = $viewBuilder;
154✔
89

90
        /** @var Arguments $arguments */
91
        $arguments = GeneralUtility::makeInstance(Arguments::class);
154✔
92
        $this->arguments = $arguments;
154✔
93

94
        /** @var Request $request */
95
        $request = $requestBuilder->buildRequestFor(
154✔
96
            $this->extensionName,
154✔
97
            'Dummy',
154✔
98
            'render',
154✔
99
            '',
154✔
100
            [],
154✔
101
        );
154✔
102
        $this->request = $request;
154✔
103
    }
104

105
    protected function initializeSettings(): void
106
    {
107
        if ($this->provider === null) {
7✔
108
            return;
×
109
        }
110
        $row = $this->getRecord();
7✔
111
        $extensionKey = $this->provider->getControllerExtensionKeyFromRecord($row);
7✔
112
        $extensionName = ExtensionNamingUtility::getExtensionName($extensionKey);
7✔
113
        $pluginName = $this->request->getPluginName();
7✔
114
        $this->settings = RecursiveArrayUtility::merge(
7✔
115
            (array) $this->configurationManager->getConfiguration(
7✔
116
                ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
7✔
117
                $extensionName,
7✔
118
                $pluginName
7✔
119
            ),
7✔
120
            (array) $this->settings
7✔
121
        );
7✔
122

123
        if ($this->provider instanceof DataStructureProviderInterface) {
7✔
124
            $this->data = $this->provider->getFlexFormValues($row);
7✔
125
        }
126

127
        $overrides = HookHandler::trigger(
7✔
128
            HookHandler::CONTROLLER_SETTINGS_INITIALIZED,
7✔
129
            [
7✔
130
                'settings' => $this->settings,
7✔
131
                'data' => $this->data,
7✔
132
                'record' => $row,
7✔
133
                'provider' => $this->provider,
7✔
134
                'controller' => $this,
7✔
135
                'request' => $this->request,
7✔
136
                'extensionKey' => $extensionKey
7✔
137
            ]
7✔
138
        );
7✔
139
        $this->data = $overrides['data'];
7✔
140
        $this->settings = $overrides['settings'];
7✔
141
        $this->provider = $overrides['provider'];
7✔
142
    }
143

144
    protected function initializeOverriddenSettings(): void
145
    {
146
        if ($this->provider === null) {
35✔
147
            return;
×
148
        }
149
        $row = $this->getRecord();
35✔
150
        $extensionKey = $this->provider->getControllerExtensionKeyFromRecord($row);
35✔
151
        $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionKey);
35✔
152
        if (is_array($this->data['settings'] ?? null)) {
35✔
153
            // a "settings." array is defined in the flexform configuration - extract it, use as "settings" in template
154
            // as well as the internal $this->settings array as per expected Extbase behavior.
155
            $this->settings = RecursiveArrayUtility::merge($this->settings, $this->data['settings'] ?? []);
28✔
156
        }
157
        if ($this->settings['useTypoScript'] ?? false) {
35✔
158
            // an override shared by all Flux enabled controllers: setting plugin.tx_EXTKEY.settings.useTypoScript = 1
159
            // will read the "settings" array from that location instead - thus excluding variables from the flexform
160
            // which are still available as $this->data but no longer available automatically in the template.
161
            $this->settings = $this->typoScriptService->getSettingsForExtensionName($extensionKey);
21✔
162
        }
163
    }
164

165
    protected function initializeProvider(): void
166
    {
167
        $row = $this->getRecord();
28✔
168
        $table = (string) $this->getFluxTableName();
28✔
169
        $field = $this->getFluxRecordField();
28✔
170
        $provider = $this->providerResolver->resolvePrimaryConfigurationProvider(
28✔
171
            $table,
28✔
172
            $field,
28✔
173
            $row,
28✔
174
            null,
28✔
175
            [ControllerProviderInterface::class]
28✔
176
        );
28✔
177
        if ($provider === null) {
28✔
178
            throw new \RuntimeException(
7✔
179
                'Unable to resolve a ConfigurationProvider, but controller indicates it is a Flux-enabled ' .
7✔
180
                'Controller - this is a grave error and indicates that EXT: ' . $this->extensionName . ' itself is ' .
7✔
181
                'broken - or that EXT:' . $this->extensionName . ' has been overridden by another implementation ' .
7✔
182
                'which is broken. The controller that caused this error was ' . get_class($this) . '".',
7✔
183
                1377458581
7✔
184
            );
7✔
185
        }
186
        $this->provider = $provider;
21✔
187
    }
188

189
    protected function initializeViewVariables(ViewInterface $view): void
190
    {
191
        $contentObject = $this->getContentObject();
7✔
192
        $row = $this->getRecord();
7✔
193

194
        $view->assign('contentObject', $contentObject);
7✔
195
        $view->assign('data', $contentObject instanceof ContentObjectRenderer ? $contentObject->data : null);
7✔
196
        if ($this->provider instanceof FluidProviderInterface) {
7✔
197
            $view->assignMultiple($this->provider->getTemplateVariables($row));
7✔
198
        }
199
        $view->assignMultiple($this->data);
7✔
200
        $view->assign('settings', $this->settings);
7✔
201
        $view->assign('provider', $this->provider);
7✔
202
        $view->assign('record', $row);
7✔
203

204
        HookHandler::trigger(
7✔
205
            HookHandler::CONTROLLER_VARIABLES_ASSIGNED,
7✔
206
            [
7✔
207
                'view' => $view,
7✔
208
                'record' => $row,
7✔
209
                'settings' => $this->settings,
7✔
210
                'provider' => $this->provider,
7✔
211
                'contentObject' => $contentObject,
7✔
212
            ]
7✔
213
        );
7✔
214
    }
215

216
    protected function initializeViewHelperVariableContainer(
217
        ViewHelperVariableContainer $viewHelperVariableContainer
218
    ): void {
219
        $viewHelperVariableContainer->add(FormViewHelper::class, 'provider', $this->provider);
7✔
220
        $viewHelperVariableContainer->add(
7✔
221
            FormViewHelper::class,
7✔
222
            'extensionName',
7✔
223
            $this->request->getControllerExtensionKey()
7✔
224
        );
7✔
225
        $viewHelperVariableContainer->add(
7✔
226
            FormViewHelper::class,
7✔
227
            'pluginName',
7✔
228
            $this->request->getPluginName()
7✔
229
        );
7✔
230
        $viewHelperVariableContainer->add(FormViewHelper::class, 'record', $this->getRecord());
7✔
231
    }
232

233
    protected function initializeAction(): void
234
    {
235
        $this->initializeProvider();
7✔
236
        $this->initializeSettings();
7✔
237
        $this->initializeOverriddenSettings();
7✔
238
    }
239

240
    protected function resolveView(): ViewInterface
241
    {
242
        if (!$this->provider instanceof ControllerProviderInterface) {
14✔
243
            throw new \RuntimeException(
×
244
                get_class($this) . ' cannot handle record; no ControllerProviderInterface could be resolved',
×
245
                1672082347
×
246
            );
×
247
        }
248

249
        $record = $this->getRecord();
14✔
250
        $extensionKey = ExtensionNamingUtility::getExtensionKey(
14✔
251
            $this->provider->getControllerExtensionKeyFromRecord($record)
14✔
252
        );
14✔
253

254
        $templatePathAndFilename = null;
14✔
255
        if ($this->provider instanceof FluidProviderInterface) {
14✔
256
            $templatePathAndFilename = $this->provider->getTemplatePathAndFilename($record);
14✔
257
        }
258

259
        $view = $this->viewBuilder->buildTemplateView(
14✔
260
            $extensionKey,
14✔
261
            $this->resolver->resolveControllerNameFromControllerClassName(get_class($this)),
14✔
262
            $this->provider->getControllerActionFromRecord($record),
14✔
263
            $this->provider->getPluginName() ?? $this->provider->getControllerNameFromRecord($record),
14✔
264
            $templatePathAndFilename,
14✔
265
            $this->request
14✔
266
        );
14✔
267

268
        $renderingContext = $view->getRenderingContext();
14✔
269

270
        $this->initializeViewVariables($view);
14✔
271
        $this->initializeViewHelperVariableContainer($renderingContext->getViewHelperVariableContainer());
14✔
272
        HookHandler::trigger(
14✔
273
            HookHandler::CONTROLLER_VIEW_INITIALIZED,
14✔
274
            [
14✔
275
                'view' => $view,
14✔
276
                'request' => $this->request,
14✔
277
                'provider' => $this->provider,
14✔
278
                'controller' => $this,
14✔
279
                'extensionKey' => $extensionKey
14✔
280
            ]
14✔
281
        );
14✔
282
        return $view;
14✔
283
    }
284

285
    /**
286
     * @return \Psr\Http\Message\ResponseInterface|Response
287
     */
288
    protected function createHtmlResponse(string $html = null)
289
    {
290
        if (method_exists($this, 'htmlResponse')) {
×
291
            return parent::htmlResponse($html);
×
292
        }
293
        $response = clone $this->response;
×
294
        $response->setContent((string) $html);
×
295
        return $response;
×
296
    }
297

298
    /**
299
     * Default action, proxy for "render". Added in order to
300
     * capture requests which use the Fluid-native "default"
301
     * action name when no specific action name is set in the
302
     * request. The "default" action is also returned by
303
     * vanilla Provider instances when registering them for
304
     * content object types or other ad-hoc registrations.
305
     *
306
     * @return \Psr\Http\Message\ResponseInterface|Response|ResponseInterface
307
     */
308
    public function defaultAction()
309
    {
310
        return $this->renderAction();
7✔
311
    }
312

313
    /**
314
     * Render content
315
     *
316
     * @return \Psr\Http\Message\ResponseInterface|Response|ResponseInterface
317
     */
318
    public function renderAction()
319
    {
320
        if (!$this->provider instanceof ControllerProviderInterface) {
14✔
321
            throw new \RuntimeException(
7✔
322
                get_class($this) . ' cannot handle record; no ControllerProviderInterface could be resolved',
7✔
323
                1672082347
7✔
324
            );
7✔
325
        }
326
        $row = $this->getRecord();
7✔
327
        $extensionKey = $this->provider->getControllerExtensionKeyFromRecord($row);
7✔
328
        $extensionSignature = ExtensionNamingUtility::getExtensionSignature($extensionKey);
7✔
329
        $pluginName = $this->request->getPluginName();
7✔
330
        $pluginSignature = strtolower('tx_' . $extensionSignature . '_' . $pluginName);
7✔
331
        $controllerExtensionKey = $this->provider->getControllerExtensionKeyFromRecord($row);
7✔
332
        $requestActionName = $this->resolveOverriddenFluxControllerActionNameFromRequestParameters($pluginSignature);
7✔
333
        $controllerActionName = $this->provider->getControllerActionFromRecord($row);
7✔
334
        $actualActionName = null !== $requestActionName ? $requestActionName : $controllerActionName;
7✔
335
        $controllerName = $this->request->getControllerName();
7✔
336

337
        return $this->performSubRendering(
7✔
338
            $controllerExtensionKey,
7✔
339
            $controllerName,
7✔
340
            $actualActionName,
7✔
341
            $pluginName,
7✔
342
            $pluginSignature
7✔
343
        );
7✔
344
    }
345

346
    protected function resolveOverriddenFluxControllerActionNameFromRequestParameters(string $pluginSignature): ?string
347
    {
348
        return $this->getServerRequest()->getQueryParams()[$pluginSignature]['action'] ?? null;
7✔
349
    }
350

351
    /**
352
     * @return \Psr\Http\Message\ResponseInterface|Response|ResponseInterface
353
     */
354
    protected function performSubRendering(
355
        string $extensionName,
356
        string $controllerName,
357
        string $actionName,
358
        string $pluginName,
359
        string $pluginSignature
360
    ) {
361
        if (property_exists($this, 'responseFactory') && $this->responseFactory instanceof ResponseFactoryInterface) {
21✔
362
            $response = $this->responseFactory->createResponse();
18✔
363
        } else {
364
            /** @var ResponseInterface $response */
365
            $response = GeneralUtility::makeInstance(Response::class);
3✔
366
        }
367

368
        $shouldRelay = $this->hasSubControllerActionOnForeignController($extensionName, $controllerName, $actionName);
21✔
369
        $foreignControllerClass = null;
21✔
370
        $content = null;
21✔
371
        if (!$shouldRelay) {
21✔
372
            if ($this->provider instanceof FluidProviderInterface) {
14✔
373
                $templatePathAndFilename = $this->provider->getTemplatePathAndFilename($this->getRecord());
7✔
374
                $vendorLessExtensionName = ExtensionNamingUtility::getExtensionName($extensionName);
7✔
375
                /** @var TemplateView $view */
376
                $view = $this->view;
7✔
377
                $renderingContext = $view->getRenderingContext();
7✔
378
                $paths = $renderingContext->getTemplatePaths();
7✔
379

380
                if (method_exists($this->request, 'setControllerExtensionName')) {
7✔
381
                    $this->request->setControllerExtensionName($vendorLessExtensionName);
4✔
382
                }
383

384
                if (method_exists($this->request, 'withControllerExtensionName')) {
7✔
385
                    $this->request = $this->request->withControllerExtensionName($vendorLessExtensionName);
6✔
386
                }
387

388
                $this->configurationManager->setConfiguration(
7✔
389
                    array_merge(
7✔
390
                        (array) $this->configurationManager->getConfiguration(
7✔
391
                            ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT,
7✔
392
                            $vendorLessExtensionName
7✔
393
                        ),
7✔
394
                        [
7✔
395
                            'extensionName' => $vendorLessExtensionName,
7✔
396
                        ]
7✔
397
                    )
7✔
398
                );
7✔
399
                $paths->setTemplatePathAndFilename((string) $templatePathAndFilename);
7✔
400
            }
401
            $content = $this->view->render();
14✔
402
        } else {
403
            $foreignControllerClass = $this->resolver->resolveFluxControllerClassNameByExtensionKeyAndControllerName(
7✔
404
                $extensionName,
7✔
405
                $controllerName
7✔
406
            );
7✔
407
            $content = $this->callSubControllerAction(
7✔
408
                $extensionName,
7✔
409
                $foreignControllerClass ?? static::class,
7✔
410
                $actionName,
7✔
411
                $pluginName,
7✔
412
                $pluginSignature
7✔
413
            );
7✔
414
        }
415
        $content = HookHandler::trigger(
21✔
416
            HookHandler::CONTROLLER_AFTER_RENDERING,
21✔
417
            [
21✔
418
                'view' => $this->view,
21✔
419
                'content' => $content,
21✔
420
                'request' => $this->request,
21✔
421
                'response' => $response,
21✔
422
                'extensionName' => $extensionName,
21✔
423
                'controllerClassName' => $foreignControllerClass,
21✔
424
                'controllerActionName' => $actionName
21✔
425
            ]
21✔
426
        )['content'];
21✔
427

428
        return $content instanceof \Psr\Http\Message\ResponseInterface || $content instanceof ResponseInterface
21✔
429
            ? $content
×
430
            : $this->createHtmlResponse($content);
21✔
431
    }
432

433
    protected function hasSubControllerActionOnForeignController(
434
        string $extensionName,
435
        string $controllerName,
436
        string $actionName
437
    ): bool {
438
        $potentialControllerClassName = $this->resolver->resolveFluxControllerClassNameByExtensionKeyAndControllerName(
7✔
439
            $extensionName,
7✔
440
            $controllerName
7✔
441
        );
7✔
442
        if ($potentialControllerClassName === null) {
7✔
443
            return false;
7✔
444
        }
445
        $isNotThis = get_class($this) !== $potentialControllerClassName;
×
446
        $isValidController = class_exists($potentialControllerClassName);
×
447
        return ($isNotThis && $isValidController
×
448
            && method_exists($potentialControllerClassName, $actionName . 'Action'));
×
449
    }
450

451
    /**
452
     * @param class-string $controllerClassName
453
     * @return \Psr\Http\Message\ResponseInterface|ResponseInterface|null
454
     */
455
    protected function callSubControllerAction(
456
        string $extensionName,
457
        string $controllerClassName,
458
        string $controllerActionName,
459
        string $pluginName,
460
        string $pluginSignature
461
    ) {
462
        $serverRequest = $this->getServerRequest();
7✔
463
        $arguments = $serverRequest->getQueryParams()[$pluginSignature] ?? [];
7✔
464
        $arguments = array_merge($arguments, ((array) $serverRequest->getParsedBody())[$pluginSignature] ?? []);
7✔
465

466
        $request = $this->requestBuilder->buildRequestFor(
7✔
467
            $extensionName,
7✔
468
            $this->resolver->resolveControllerNameFromControllerClassName(
7✔
469
                $controllerClassName
7✔
470
            ),
7✔
471
            $controllerActionName,
7✔
472
            $pluginName,
7✔
473
            $arguments,
7✔
474
            $serverRequest->getAttributes()
7✔
475
        );
7✔
476

477
        /** @var ControllerInterface $potentialControllerInstance */
478
        $potentialControllerInstance = GeneralUtility::makeInstance($controllerClassName);
7✔
479

480
        if (property_exists($this, 'responseFactory') && $this->responseFactory instanceof ResponseFactoryInterface) {
7✔
481
            /** @var ResponseInterface\ $response */
482
            $response = $this->responseFactory->createResponse();
6✔
483
        } else {
484
            /** @var ResponseInterface $response */
485
            $response = GeneralUtility::makeInstance(Response::class);
1✔
486
        }
487

488
        try {
489
            HookHandler::trigger(
7✔
490
                HookHandler::CONTROLLER_BEFORE_REQUEST,
7✔
491
                [
7✔
492
                    'request' => $this->request,
7✔
493
                    'response' => $response,
7✔
494
                    'extensionName' => $extensionName,
7✔
495
                    'controllerClassName' => $controllerClassName,
7✔
496
                    'controllerActionName' => $controllerActionName
7✔
497
                ]
7✔
498
            );
7✔
499

500
            /** @var \Psr\Http\Message\ResponseInterface|ResponseInterface|null $responseFromCall */
501
            $responseFromCall = $potentialControllerInstance->processRequest($request, $response);
7✔
502
            if ($responseFromCall) {
7✔
503
                $response = $responseFromCall;
7✔
504
            }
505
        } catch (StopActionException $error) {
×
506
            // intentionally left blank
507
        }
508
        HookHandler::trigger(
7✔
509
            HookHandler::CONTROLLER_AFTER_REQUEST,
7✔
510
            [
7✔
511
                'request' => $this->request,
7✔
512
                'response' => $response,
7✔
513
                'extensionName' => $extensionName,
7✔
514
                'controllerClassName' => $controllerClassName,
7✔
515
                'controllerActionName' => $controllerActionName
7✔
516
            ]
7✔
517
        );
7✔
518

519
        return $response;
7✔
520
    }
521

522
    /**
523
     * Get the data stored in a record's Flux-enabled field,
524
     * i.e. the variables of the Flux template as configured in this
525
     * particular record.
526
     */
527
    protected function getData(): array
528
    {
529
        return $this->data;
7✔
530
    }
531

532
    protected function getFluxRecordField(): ?string
533
    {
534
        return $this->fluxRecordField;
21✔
535
    }
536

537
    protected function getFluxTableName(): ?string
538
    {
539
        return $this->fluxTableName;
35✔
540
    }
541

542
    public function getRecord(): array
543
    {
544
        if ($this->record !== null) {
28✔
545
            return $this->record;
14✔
546
        }
547

548
        $contentObject = $this->getContentObject();
28✔
549
        if ($contentObject === null) {
28✔
550
            throw new \UnexpectedValueException(
7✔
551
                "Record of table " . $this->getFluxTableName() . ' not found',
7✔
552
                1666538343
7✔
553
            );
7✔
554
        }
555

556
        if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '11.5', '<')) {
21✔
557
            /** @var TypoScriptFrontendController|null $tsfe */
558
            $tsfe = $GLOBALS['TSFE'] ?? null;
3✔
559
        } else {
560
            $tsfe = $contentObject->getTypoScriptFrontendController();
18✔
561
        }
562
        if ($tsfe === null) {
21✔
563
            throw new \UnexpectedValueException(
×
564
                "Record of table " . $this->getFluxTableName() . ' not found',
×
565
                1729864782
×
566
            );
×
567
        }
568

569
        if (!empty($contentObject->data)) {
21✔
NEW
570
            return $this->record = $contentObject->data;
×
571
        }
572

573
        [$table, $recordUid] = GeneralUtility::trimExplode(
21✔
574
            ':',
21✔
575
            $tsfe->currentRecord ?: $contentObject->currentRecord
21✔
576
        );
21✔
577
        $record = $this->recordService->getSingle($table, '*', (integer) $recordUid);
21✔
578
        if ($record === null) {
21✔
579
            throw new \UnexpectedValueException(
×
580
                "Record of table " . $this->getFluxTableName() . ' not found',
×
581
                1729864698
×
582
            );
×
583
        }
584

585
        if ($record['_LOCALIZED_UID'] ?? false) {
21✔
586
            $record = array_merge(
×
587
                $record,
×
588
                $this->recordService->getSingle(
×
589
                    (string) $this->getFluxTableName(),
×
590
                    '*',
×
591
                    $record['_LOCALIZED_UID']
×
592
                ) ?? $record
×
593
            );
×
594
        }
595
        return $this->record = $record;
21✔
596
    }
597

598
    protected function getContentObject(): ?ContentObjectRenderer
599
    {
NEW
600
        return ContentObjectFetcher::resolve(
×
NEW
601
            $this->configurationManager,
×
NEW
602
            $this->request instanceof ServerRequestInterface ? $this->request : null
×
NEW
603
        );
×
604
    }
605

606
    protected function getServerRequest(): ServerRequestInterface
607
    {
NEW
608
        if ($this->request instanceof ServerRequestInterface) {
×
NEW
609
            return $this->request;
×
610
        }
611
        /** @var ServerRequestInterface $request */
612
        $request = $GLOBALS['TYPO3_REQUEST'];
×
613
        return $request;
×
614
    }
615
}
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