From e94271f6d9f56f960fdda83eb190a363fdb0c68c Mon Sep 17 00:00:00 2001
From: Benjamin Franzke <ben@bnf.dev>
Date: Thu, 22 Feb 2024 08:24:34 +0100
Subject: [PATCH] [BUGFIX] Allow TCA resultArray modification via
 CustomFileControlsEvent

The event provides access to the `$resultArray` and documents
that it can be modified to set `javaScriptModules`, but missed
to take the resulting data into account.

Releases: main, 12.4
Resolves: #103174
Change-Id: I0a53d1fbcdff0a3d57de237b44d3ff68f60c721d
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/83072
Tested-by: core-ci <typo3@b13.com>
Tested-by: Andreas Kienast <a.fernandez@scripting-base.de>
Tested-by: Benjamin Franzke <ben@bnf.dev>
Reviewed-by: Andreas Kienast <a.fernandez@scripting-base.de>
Tested-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Benjamin Franzke <ben@bnf.dev>
Reviewed-by: Oliver Bartsch <bo@cedev.de>
---
 .../Form/Container/FilesControlContainer.php  |   6 +-
 .../Container/FilesControlContainerTest.php   | 110 ++++++++++++++++++
 2 files changed, 114 insertions(+), 2 deletions(-)
 create mode 100644 typo3/sysext/backend/Tests/Functional/Form/Container/FilesControlContainerTest.php

diff --git a/typo3/sysext/backend/Classes/Form/Container/FilesControlContainer.php b/typo3/sysext/backend/Classes/Form/Container/FilesControlContainer.php
index c231c8d07621..b213f3b1339c 100644
--- a/typo3/sysext/backend/Classes/Form/Container/FilesControlContainer.php
+++ b/typo3/sysext/backend/Classes/Form/Container/FilesControlContainer.php
@@ -271,9 +271,11 @@ class FilesControlContainer extends AbstractContainer
             }
         }
 
-        $controls = $this->eventDispatcher->dispatch(
+        $event = $this->eventDispatcher->dispatch(
             new CustomFileControlsEvent($resultArray, $table, $field, $row, $config, $formFieldIdentifier, $formFieldName)
-        )->getControls();
+        );
+        $resultArray = $event->getResultArray();
+        $controls = $event->getControls();
 
         if ($controls !== []) {
             $view->assign('customControls', [
diff --git a/typo3/sysext/backend/Tests/Functional/Form/Container/FilesControlContainerTest.php b/typo3/sysext/backend/Tests/Functional/Form/Container/FilesControlContainerTest.php
new file mode 100644
index 000000000000..1c41f77bd47f
--- /dev/null
+++ b/typo3/sysext/backend/Tests/Functional/Form/Container/FilesControlContainerTest.php
@@ -0,0 +1,110 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Backend\Tests\Functional\Form\Container;
+
+use Symfony\Component\DependencyInjection\Container;
+use TYPO3\CMS\Backend\Form\Container\FilesControlContainer;
+use TYPO3\CMS\Backend\Form\Event\CustomFileControlsEvent;
+use TYPO3\CMS\Backend\Routing\Route;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder;
+use TYPO3\CMS\Core\EventDispatcher\ListenerProvider;
+use TYPO3\CMS\Core\Http\ServerRequest;
+use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
+
+final class FilesControlContainerTest extends FunctionalTestCase
+{
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $GLOBALS['BE_USER'] = new BackendUserAuthentication();
+        $GLOBALS['LANG'] = $this->get(LanguageServiceFactory::class)->create('default');
+    }
+
+    /**
+     * @test
+     */
+    public function customFileControlsEventIsCalled(): void
+    {
+        $customFileControlsEvent = null;
+        $controls = ['foo', 'bar'];
+        $databaseRow = [
+            'uid' => 123,
+        ];
+        $fieldConfig = [
+            'minitems' => 1,
+            'maxitems' => 2,
+        ];
+        $fieldName = 'assets';
+        $tableName = 'tx_table';
+        $formFieldIdentifier = 'data-123-tx_table-123-assets';
+        $formFieldName = 'data[tx_table][123][assets]';
+
+        /** @var Container $container */
+        $container = $this->get('service_container');
+        $container->set(
+            'custom-file-controls-listener',
+            static function (CustomFileControlsEvent $event) use (&$customFileControlsEvent, $controls) {
+                $customFileControlsEvent = $event;
+                $event->setControls($controls);
+                $event->setResultArray(['javaScriptModules' => ['fooJavaScriptModule']]);
+            }
+        );
+
+        $eventListener = $this->get(ListenerProvider::class);
+        $eventListener->addListener(CustomFileControlsEvent::class, 'custom-file-controls-listener');
+
+        $subject = $this->get(FilesControlContainer::class);
+        $subject->setData([
+            'inlineData' => [],
+            'inlineStructure' => [],
+            'inlineFirstPid' => 123,
+            'fieldName' => $fieldName,
+            'tableName' => $tableName,
+            'renderType' => 'file',
+            'databaseRow' => $databaseRow,
+            'tabAndInlineStack' => '',
+            'request' => (new ServerRequest())
+                ->withAttribute('route', new Route('', []))
+                ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_BE),
+            'parameterArray' => [
+                'itemFormElName' => '',
+                'fieldConf' => [
+                    'label' => 'foobar',
+                    'config' => $fieldConfig,
+                    'children' => [],
+                ],
+            ],
+            'returnUrl' => '',
+        ]);
+        $result = $subject->render();
+
+        self::assertInstanceOf(CustomFileControlsEvent::class, $customFileControlsEvent);
+        self::assertContains('fooJavaScriptModule', $result['javaScriptModules']);
+        self::assertContains('fooJavaScriptModule', $customFileControlsEvent->getResultArray()['javaScriptModules']);
+        self::assertEquals($controls, $customFileControlsEvent->getControls());
+        self::assertEquals($databaseRow, $customFileControlsEvent->getDatabaseRow());
+        self::assertArrayHasKey('minitems', $customFileControlsEvent->getFieldConfig());
+        self::assertArrayHasKey('maxitems', $customFileControlsEvent->getFieldConfig());
+        self::assertEquals($fieldName, $customFileControlsEvent->getFieldName());
+        self::assertEquals($formFieldIdentifier, $customFileControlsEvent->getFormFieldIdentifier());
+        self::assertEquals($formFieldName, $customFileControlsEvent->getFormFieldName());
+        self::assertEquals($tableName, $customFileControlsEvent->getTableName());
+    }
+}
-- 
GitLab