diff --git a/config/v12/flexform-120.php b/config/v12/flexform-120.php
index 77517fd50..70fc4a268 100644
--- a/config/v12/flexform-120.php
+++ b/config/v12/flexform-120.php
@@ -9,6 +9,7 @@
use Ssch\TYPO3Rector\Rector\v12\v0\flexform\MigrateNullFlagFlexFormRector;
use Ssch\TYPO3Rector\Rector\v12\v0\flexform\MigratePasswordAndSaltedPasswordToPasswordTypeFlexFormRector;
use Ssch\TYPO3Rector\Rector\v12\v0\flexform\MigrateRenderTypeColorpickerToTypeColorFlexFormRector;
+use Ssch\TYPO3Rector\Rector\v12\v0\flexform\MigrateRequiredFlagFlexFormRector;
use Ssch\TYPO3Rector\Rector\v12\v0\flexform\RemoveElementTceFormsRector;
return static function (RectorConfig $rectorConfig): void {
@@ -19,5 +20,6 @@
$rectorConfig->rule(MigrateNullFlagFlexFormRector::class);
$rectorConfig->rule(MigratePasswordAndSaltedPasswordToPasswordTypeFlexFormRector::class);
$rectorConfig->rule(MigrateRenderTypeColorpickerToTypeColorFlexFormRector::class);
+ $rectorConfig->rule(MigrateRequiredFlagFlexFormRector::class);
$rectorConfig->rule(RemoveElementTceFormsRector::class);
};
diff --git a/src/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector.php b/src/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector.php
new file mode 100644
index 000000000..c276119d1
--- /dev/null
+++ b/src/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector.php
@@ -0,0 +1,135 @@
+ $elements */
+ $elements = $xpath->query('//config');
+
+ if ($elements->count() === 0) {
+ return false;
+ }
+
+ foreach ($elements as $element) {
+ $this->refactorColumn($domDocument, $element);
+ }
+
+ return $this->domDocumentHasBeenChanged;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ */
+ public function getRuleDefinition(): RuleDefinition
+ {
+ return new RuleDefinition('Migrate required flag', [new CodeSample(
+ <<<'CODE_SAMPLE'
+
+
+ aTitle
+ array
+
+
+ foo
+
+ trim,required
+
+
+
+
+
+CODE_SAMPLE
+ ,
+ <<<'CODE_SAMPLE'
+
+
+ aTitle
+ array
+
+
+ foo
+
+ trim
+ 1
+
+
+
+
+
+CODE_SAMPLE
+ )]);
+ }
+
+ private function refactorColumn(DOMDocument $domDocument, ?DOMElement $configElement): void
+ {
+ if (! $configElement instanceof DOMElement) {
+ return;
+ }
+
+ if (! $this->hasKey($configElement, 'eval')) {
+ return;
+ }
+
+ $evalDomElement = $this->extractDomElementByKey($configElement, 'eval');
+ if (! $evalDomElement instanceof DOMElement) {
+ return;
+ }
+
+ $evalListValue = $evalDomElement->nodeValue;
+ if (! is_string($evalListValue)) {
+ return;
+ }
+
+ if (! StringUtility::inList($evalListValue, 'required')) {
+ return;
+ }
+
+ $evalList = ArrayUtility::trimExplode(',', $evalListValue, true);
+
+ // Remove "required" from $evalList
+ $evalList = array_filter($evalList, static fn (string $eval) => $eval !== 'required');
+
+ if ($evalList !== []) {
+ // Write back filtered 'eval'
+ $evalDomElement->nodeValue = '';
+ $evalDomElement->appendChild($domDocument->createTextNode(implode(',', $evalList)));
+ } elseif ($evalDomElement->parentNode instanceof DOMElement) {
+ // 'eval' is empty, remove whole configuration
+ $evalDomElement->parentNode->removeChild($evalDomElement);
+ }
+
+ $requiredDomElement = $this->extractDomElementByKey($configElement, 'required');
+ if (! $requiredDomElement instanceof DOMElement) {
+ $configElement->appendChild($domDocument->createElement('required', '1'));
+ }
+
+ $this->domDocumentHasBeenChanged = true;
+ }
+}
diff --git a/src/Rector/v12/v0/tca/MigrateRequiredFlagRector.php b/src/Rector/v12/v0/tca/MigrateRequiredFlagRector.php
index b15bab577..70867abff 100644
--- a/src/Rector/v12/v0/tca/MigrateRequiredFlagRector.php
+++ b/src/Rector/v12/v0/tca/MigrateRequiredFlagRector.php
@@ -19,6 +19,7 @@
/**
* @changelog https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/12.0/Deprecation-97035-RequiredOptionInEvalKeyword.html
+ * @changelog https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/12.0/Feature-97035-UtilizeRequiredDirectlyInTCAFieldConfiguration.html
* @see \Ssch\TYPO3Rector\Tests\Rector\v12\v0\tca\MigrateRequiredFlagRector\MigrateRequiredFlagRectorTest
*/
final class MigrateRequiredFlagRector extends AbstractTcaRector
diff --git a/tests/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector/Fixture/fixture.xml.inc b/tests/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector/Fixture/fixture.xml.inc
new file mode 100644
index 000000000..60fbc3cdf
--- /dev/null
+++ b/tests/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector/Fixture/fixture.xml.inc
@@ -0,0 +1,70 @@
+
+
+
+
+ sheetTitle
+ array
+
+
+
+ input
+ required
+
+
+
+
+ input
+ trim,required
+
+
+
+
+ input
+ trim
+
+
+
+
+ input
+
+
+
+
+
+
+
+-----
+
+
+
+
+ sheetTitle
+ array
+
+
+
+ input
+ 1
+
+
+
+ input
+ trim
+ 1
+
+
+
+ input
+ trim
+
+
+
+
+ input
+
+
+
+
+
+
+
diff --git a/tests/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector/MigrateRequiredFlagFlexFormRectorTest.php b/tests/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector/MigrateRequiredFlagFlexFormRectorTest.php
new file mode 100644
index 000000000..de6d305e5
--- /dev/null
+++ b/tests/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector/MigrateRequiredFlagFlexFormRectorTest.php
@@ -0,0 +1,32 @@
+doTestFile($filePath);
+ }
+
+ /**
+ * @return Iterator>
+ */
+ public function provideData(): Iterator
+ {
+ return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture', '*.xml.inc');
+ }
+
+ public function provideConfigFilePath(): string
+ {
+ return __DIR__ . '/config/configured_rule.php';
+ }
+}
diff --git a/tests/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector/config/configured_rule.php b/tests/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector/config/configured_rule.php
new file mode 100644
index 000000000..cba20b548
--- /dev/null
+++ b/tests/Rector/v12/v0/flexform/MigrateRequiredFlagFlexFormRector/config/configured_rule.php
@@ -0,0 +1,11 @@
+import(__DIR__ . '/../../../../../../../config/config_test.php');
+ $rectorConfig->rule(MigrateRequiredFlagFlexFormRector::class);
+};