diff --git a/.gitattributes b/.gitattributes index 6c6b531..50bcb4d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,20 +1,21 @@ -* text=auto -/.ddev export-ignore -/.github export-ignore -/Build export-ignore -/Tests export-ignore -/.editorconfig export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.php-cs-fixer.php export-ignore -/composer.lock export-ignore -/docker-compose.yml export-ignore -/packaging_exclude.php export-ignore -/phpstan.neon export-ignore -/phpstan-baseline.neon export-ignore -/phpunit.functional.xml export-ignore -/phpunit.unit.xml export-ignore -/rector.php export-ignore -/renovate.json export-ignore -/typoscript-lint.yml export-ignore -/version-bumper.yaml export-ignore +* text=auto +/.ddev export-ignore +/.github export-ignore +/Build export-ignore +/Tests export-ignore +/.editorconfig export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.php-cs-fixer.php export-ignore +/composer.lock export-ignore +/composer-dependency-analyser.php export-ignore +/docker-compose.yml export-ignore +/packaging_exclude.php export-ignore +/phpstan.neon export-ignore +/phpstan-baseline.neon export-ignore +/phpunit.functional.xml export-ignore +/phpunit.unit.xml export-ignore +/rector.php export-ignore +/renovate.json export-ignore +/typoscript-lint.yml export-ignore +/version-bumper.yaml export-ignore diff --git a/Classes/ContentObject/CanUpdateRegister.php b/Classes/ContentObject/CanUpdateRegister.php new file mode 100644 index 0000000..5fdfed8 --- /dev/null +++ b/Classes/ContentObject/CanUpdateRegister.php @@ -0,0 +1,72 @@ + + * @license GPL-2.0-or-later + * @internal + * + * @property Message\ServerRequestInterface $request + */ +trait CanUpdateRegister +{ + protected Core\Information\Typo3Version $typo3Version; + + protected function updateRegister(string $key, ?int $value = null): void + { + match ($this->typo3Version->getMajorVersion()) { + 13 => $this->modifyRegisterUsingTsfe($key, $value), + 14 => $this->modifyRegisterUsingRequest($key, $value), + default => null, + }; + } + + /** + * @todo Remove once support for TYPO3 v13 is dropped + */ + protected function modifyRegisterUsingTsfe(string $key, ?int $value): void + { + $tsfe = $this->getTypoScriptFrontendController(); + + if ($value === null) { + unset($tsfe->register[$key]); + } else { + $tsfe->register[$key] = $value; + } + } + + protected function modifyRegisterUsingRequest(string $key, ?int $value): void + { + $stack = $this->request->getAttribute('frontend.register.stack'); + + if (!($stack instanceof Frontend\ContentObject\RegisterStack)) { + return; + } + + if ($value !== null) { + $stack->current()->set($key, $value); + } + } +} diff --git a/Classes/ContentObject/ChildrenContentObject.php b/Classes/ContentObject/ChildrenContentObject.php index f7644d3..72ca5b4 100644 --- a/Classes/ContentObject/ChildrenContentObject.php +++ b/Classes/ContentObject/ChildrenContentObject.php @@ -19,6 +19,7 @@ use CPSIT\Typo3HandlebarsForms\Domain; use Symfony\Component\DependencyInjection; +use TYPO3\CMS\Core; /** * ChildrenContentObject @@ -29,9 +30,16 @@ #[DependencyInjection\Attribute\AutoconfigureTag('frontend.contentobject', ['identifier' => 'HBS_CHILDREN'])] final class ChildrenContentObject extends AbstractHandlebarsFormsContentObject { + use CanUpdateRegister; + private const IDENTIFIER_COUNT = 'HBS_CHILDREN_COUNT'; private const IDENTIFIER_CURRENT = 'HBS_CHILDREN_CURRENT'; + public function __construct() + { + $this->typo3Version = new Core\Information\Typo3Version(); + } + /** * @return list|null */ @@ -49,23 +57,21 @@ protected function resolve(array $configuration, Context\ValueResolutionContext $processedValue = []; - // Add children count to TSFE register - // @todo Use $this->request->getAttribute('frontend.register.stack') in TYPO3 v14 - $tsfe = $this->getTypoScriptFrontendController(); - $tsfe->register[self::IDENTIFIER_COUNT] = count($children); + // Add children count to register + $this->updateRegister(self::IDENTIFIER_COUNT, count($children)); foreach ($children as $index => $childViewModel) { // Add current child index to TSFE register - $tsfe->register[self::IDENTIFIER_CURRENT] = $index; + $this->updateRegister(self::IDENTIFIER_CURRENT, count($children)); try { $processedValue[] = $context->process($configuration, viewModel: $childViewModel); } finally { - unset($tsfe->register[self::IDENTIFIER_CURRENT]); + $this->updateRegister(self::IDENTIFIER_CURRENT); } } - unset($tsfe->register[self::IDENTIFIER_COUNT]); + $this->updateRegister(self::IDENTIFIER_COUNT); return $processedValue; } diff --git a/Classes/ContentObject/RenderablesContentObject.php b/Classes/ContentObject/RenderablesContentObject.php index 3340938..15fd87f 100644 --- a/Classes/ContentObject/RenderablesContentObject.php +++ b/Classes/ContentObject/RenderablesContentObject.php @@ -19,6 +19,7 @@ use CPSIT\Typo3HandlebarsForms\Domain; use Symfony\Component\DependencyInjection; +use TYPO3\CMS\Core; use TYPO3\CMS\Fluid; use TYPO3\CMS\Form; @@ -31,6 +32,8 @@ #[DependencyInjection\Attribute\AutoconfigureTag('frontend.contentobject', ['identifier' => 'HBS_RENDERABLES'])] final class RenderablesContentObject extends AbstractHandlebarsFormsContentObject { + use CanUpdateRegister; + private const IDENTIFIER_COUNT = 'HBS_RENDERABLES_COUNT'; private const IDENTIFIER_CURRENT = 'HBS_RENDERABLES_CURRENT'; @@ -42,7 +45,9 @@ public function __construct( private readonly iterable $viewModelBuilders, private readonly Context\ContextStack $contextStack, private readonly Context\ValueCollector $valueCollector, - ) {} + ) { + $this->typo3Version = new Core\Information\Typo3Version(); + } /** * @return list @@ -99,9 +104,7 @@ protected function resolve(array $configuration, Context\ValueResolutionContext } // Add renderables count to TSFE register - // @todo Use $this->request->getAttribute('frontend.register.stack') in TYPO3 v14 - $tsfe = $this->getTypoScriptFrontendController(); - $tsfe->register[self::IDENTIFIER_COUNT] = count($renderables); + $this->updateRegister(self::IDENTIFIER_COUNT, count($renderables)); foreach ($renderables as $index => $child) { if (!$this->isEnabled($child)) { @@ -109,7 +112,7 @@ protected function resolve(array $configuration, Context\ValueResolutionContext } // Add current renderable index to TSFE register - $tsfe->register[self::IDENTIFIER_CURRENT] = $index; + $this->updateRegister(self::IDENTIFIER_CURRENT, $index); try { if (array_key_exists($child->getType() . '.', $configuration)) { @@ -145,11 +148,11 @@ protected function resolve(array $configuration, Context\ValueResolutionContext $processedRenderables[] = $processedChild; } } finally { - unset($tsfe->register[self::IDENTIFIER_CURRENT]); + $this->updateRegister(self::IDENTIFIER_CURRENT); } } - unset($tsfe->register[self::IDENTIFIER_COUNT]); + $this->updateRegister(self::IDENTIFIER_COUNT); return $processedRenderables; } diff --git a/Classes/Domain/Renderer/HandlebarsFormRenderer.php b/Classes/Domain/Renderer/HandlebarsFormRenderer.php index 26adf14..59631e7 100644 --- a/Classes/Domain/Renderer/HandlebarsFormRenderer.php +++ b/Classes/Domain/Renderer/HandlebarsFormRenderer.php @@ -18,6 +18,7 @@ namespace CPSIT\Typo3HandlebarsForms\Domain\Renderer; use CPSIT\Typo3Handlebars\View; +use Psr\EventDispatcher; use Symfony\Component\DependencyInjection; use TYPO3\CMS\Core; use TYPO3\CMS\Extbase; @@ -39,6 +40,7 @@ public function __construct( private readonly Extbase\Configuration\ConfigurationManagerInterface $configurationManager, private readonly View\HandlebarsViewFactory $viewFactory, private readonly Core\TypoScript\TypoScriptService $typoScriptService, + private readonly EventDispatcher\EventDispatcherInterface $eventDispatcher, ) { $this->typo3Version = new Core\Information\Typo3Version(); } @@ -172,13 +174,10 @@ private function triggerBeforeRenderingHook(): void } } - /** - * @todo Enable once support for TYPO3 v14 is added - */ private function triggerBeforeRenderableIsRenderedEvent(): void { - // $this->eventDispatcher->dispatch( - // new Form\Event\BeforeRenderableIsRenderedEvent($this->formRuntime->getFormDefinition(), $this->formRuntime), - // ); + $this->eventDispatcher->dispatch( + new Form\Event\BeforeRenderableIsRenderedEvent($this->formRuntime->getFormDefinition(), $this->formRuntime), + ); } } diff --git a/Documentation/Installation/Index.rst b/Documentation/Installation/Index.rst index c1920bf..e8a43d7 100644 --- a/Documentation/Installation/Index.rst +++ b/Documentation/Installation/Index.rst @@ -12,7 +12,7 @@ Requirements ============ - PHP 8.2 - 8.5 -- TYPO3 13.4 LTS +- TYPO3 13.4 LTS - 14.3 LTS .. _steps: diff --git a/Documentation/Introduction/Index.rst b/Documentation/Introduction/Index.rst index 6673f96..7808e17 100644 --- a/Documentation/Introduction/Index.rst +++ b/Documentation/Introduction/Index.rst @@ -28,7 +28,7 @@ Features - Ability to define generic form rendering definitions - Possibility to override form rendering for specific form definitions - Easy to extend and customize for custom form elements -- Compatible with TYPO3 13.4 LTS +- Compatible with TYPO3 13.4 LTS and 14.3 LTS .. _support: diff --git a/README.md b/README.md index bfe0fac..11ea922 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ configured using dedicated interface implementations. * Ability to define generic form rendering definitions * Possibility to override form rendering for specific form definitions * Easy to extend and customize for custom form elements -* Compatible with TYPO3 13.4 LTS +* Compatible with TYPO3 13.4 LTS and 14.3 LTS ## 🔥 Installation diff --git a/composer-dependency-analyser.php b/composer-dependency-analyser.php new file mode 100644 index 0000000..7842810 --- /dev/null +++ b/composer-dependency-analyser.php @@ -0,0 +1,34 @@ +addPathToScan('Classes', false) + ->addPathToScan('Configuration', false) + ->addPathToScan('Tests', true) + ->ignoreUnknownClasses([ + // @todo Remove once support for TYPO3 v13 is dropped + Form\Event\BeforeRenderableIsRenderedEvent::class, + Frontend\ContentObject\RegisterStack::class, + ]) +; + +return $configuration; diff --git a/composer.json b/composer.json index 12260f1..13d5a21 100644 --- a/composer.json +++ b/composer.json @@ -18,15 +18,16 @@ "ext-libxml": "*", "cpsit/typo3-handlebars": "^1.0@alpha", "devtheorem/php-handlebars": "^2.0", + "psr/event-dispatcher": "^1.0", "psr/http-message": "^1.0 || ^2.0", "psr/log": "^3.0", "symfony/dependency-injection": "^7.0", - "typo3/cms-core": "~13.4.0", - "typo3/cms-extbase": "~13.4.0", - "typo3/cms-fluid": "~13.4.0", - "typo3/cms-form": "~13.4.0", - "typo3/cms-frontend": "~13.4.0", - "typo3fluid/fluid": "^4.0" + "typo3/cms-core": "~13.4.0 || ~14.3.0", + "typo3/cms-extbase": "~13.4.0 || ~14.3.0", + "typo3/cms-fluid": "~13.4.0 || ~14.3.0", + "typo3/cms-form": "~13.4.0 || ~14.3.0", + "typo3/cms-frontend": "~13.4.0 || ~14.3.0", + "typo3fluid/fluid": "^4.0 || ^5.0" }, "require-dev": { "armin/editorconfig-cli": "^2.0", @@ -42,13 +43,13 @@ "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpcov": "^10.0 || ^11.0 || ^12.0 || ^13.0", "phpunit/phpunit": "^11.5 || ^12.5 || ^13.0", - "saschaegerer/phpstan-typo3": "^2.1", + "saschaegerer/phpstan-typo3": "^2.1 || ^3.0", "shipmonk/composer-dependency-analyser": "^1.8", "ssch/typo3-rector": "^3.11", - "typo3/cms-install": "~13.4.0", - "typo3/cms-tstemplate": "~13.4.0", + "typo3/cms-install": "~13.4.0 || ~14.3.0", + "typo3/cms-tstemplate": "~13.4.0 || ~14.3.0", "typo3/coding-standards": "^0.8.0", - "typo3/testing-framework": "^9.3.0" + "typo3/testing-framework": "^9.5.0" }, "repositories": [ { diff --git a/composer.lock b/composer.lock index 516a5af..bbfc862 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fea9a00fc98ae939542288775521347e", + "content-hash": "d160ac923a30e9f44d0a6dfd96185275", "packages": [ { "name": "bacon/bacon-qr-code", diff --git a/packaging_exclude.php b/packaging_exclude.php index e15630c..c820fc0 100644 --- a/packaging_exclude.php +++ b/packaging_exclude.php @@ -28,6 +28,7 @@ 'files' => [ 'DS_Store', 'composer.lock', + 'composer-dependency-analyser.php', 'docker-compose.yml', 'editorconfig', 'gitattributes', diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index fb2eb36..8c98635 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -8,7 +8,25 @@ parameters: files. The class should vanish together with $GLOBALS['TSFE'] in v14. ''' identifier: property.deprecatedClass - count: 4 + count: 2 + path: Classes/ContentObject/ChildrenContentObject.php + + - + rawMessage: 'Call to method current() on an unknown class TYPO3\CMS\Frontend\ContentObject\RegisterStack.' + identifier: class.notFound + count: 1 + path: Classes/ContentObject/ChildrenContentObject.php + + - + rawMessage: 'Cannot call method set() on mixed.' + identifier: method.nonObject + count: 1 + path: Classes/ContentObject/ChildrenContentObject.php + + - + rawMessage: Class TYPO3\CMS\Frontend\ContentObject\RegisterStack not found. + identifier: class.notFound + count: 1 path: Classes/ContentObject/ChildrenContentObject.php - @@ -31,7 +49,25 @@ parameters: files. The class should vanish together with $GLOBALS['TSFE'] in v14. ''' identifier: property.deprecatedClass - count: 4 + count: 2 + path: Classes/ContentObject/RenderablesContentObject.php + + - + rawMessage: 'Call to method current() on an unknown class TYPO3\CMS\Frontend\ContentObject\RegisterStack.' + identifier: class.notFound + count: 1 + path: Classes/ContentObject/RenderablesContentObject.php + + - + rawMessage: 'Cannot call method set() on mixed.' + identifier: method.nonObject + count: 1 + path: Classes/ContentObject/RenderablesContentObject.php + + - + rawMessage: Class TYPO3\CMS\Frontend\ContentObject\RegisterStack not found. + identifier: class.notFound + count: 1 path: Classes/ContentObject/RenderablesContentObject.php - @@ -63,3 +99,9 @@ parameters: identifier: offsetAccess.nonOffsetAccessible count: 1 path: Classes/Domain/Renderer/HandlebarsFormRenderer.php + + - + rawMessage: Instantiated class TYPO3\CMS\Form\Event\BeforeRenderableIsRenderedEvent not found. + identifier: class.notFound + count: 1 + path: Classes/Domain/Renderer/HandlebarsFormRenderer.php diff --git a/phpstan.neon b/phpstan.neon index 86c398f..a960751 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -9,3 +9,6 @@ parameters: - Tests featureToggles: internalTag: false + typo3: + requestGetAttributeMapping: + frontend.register.stack: TYPO3\CMS\Frontend\ContentObject\RegisterStack|null