From 1ff4a177ca49a4cfb9b1662a137799abd874ff69 Mon Sep 17 00:00:00 2001 From: Sebastian Michaelsen Date: Sat, 3 Aug 2024 18:20:09 +0200 Subject: [PATCH] feat: register component classes with custom PHP attribute WIP: The generated TypoScript is loaded very early, before the TypoScript Sets from extensions. This way, at the moment we can *not* override the rendering from other extensions like fluid_styled_content. Look if we can generate the TypoScript into the set of the host extension. --- .../Attribute/ComponentForContentElements.php | 15 ++++++ .../CompilerPass/ComponentPass.php | 48 +++++++++++++++++ .../ContainerBuilding/ComponentRegistry.php | 33 ++++++++++++ .../ComponentRegistryEntry.php | 30 +++++++++++ .../AddComponentsToTypoScript.php | 51 +++++++++++++++++++ Configuration/Services.php | 21 ++++++++ README.md | 11 ++-- 7 files changed, 204 insertions(+), 5 deletions(-) create mode 100644 Classes/ContainerBuilding/Attribute/ComponentForContentElements.php create mode 100644 Classes/ContainerBuilding/CompilerPass/ComponentPass.php create mode 100644 Classes/ContainerBuilding/ComponentRegistry.php create mode 100644 Classes/ContainerBuilding/ComponentRegistryEntry.php create mode 100644 Classes/ContainerBuilding/EventListener/AddComponentsToTypoScript.php create mode 100644 Configuration/Services.php diff --git a/Classes/ContainerBuilding/Attribute/ComponentForContentElements.php b/Classes/ContainerBuilding/Attribute/ComponentForContentElements.php new file mode 100644 index 0000000..202e3d8 --- /dev/null +++ b/Classes/ContainerBuilding/Attribute/ComponentForContentElements.php @@ -0,0 +1,15 @@ +collectComponentRegistryEntries($container); + $componentRegistryDefinition = $container->findDefinition(ComponentRegistry::class); + foreach ($componentRegistryEntries as $componentRegistryEntry) { + $componentRegistryDefinition->addMethodCall( + 'registerComponent', + [ + $componentRegistryEntry->componentClassname, + $componentRegistryEntry->getCTypes(), + ] + ); + } + } + + /** + * @return iterable + */ + private function collectComponentRegistryEntries(ContainerBuilder $container): iterable + { + $componentClasses = []; + foreach ($container->findTaggedServiceIds($this->tagName) as $serviceName => $tags) { + $componentRegistryEntry = new ComponentRegistryEntry($serviceName); + foreach ($tags as $attribute) { + $componentRegistryEntry->addCType($attribute['cType']); + } + $componentClasses[] = $componentRegistryEntry; + } + return $componentClasses; + } +} diff --git a/Classes/ContainerBuilding/ComponentRegistry.php b/Classes/ContainerBuilding/ComponentRegistry.php new file mode 100644 index 0000000..430f928 --- /dev/null +++ b/Classes/ContainerBuilding/ComponentRegistry.php @@ -0,0 +1,33 @@ + + */ + private array $componentRegistryEntries = []; + + /** + * @param iterable $cTypes + */ + public function registerComponent(string $serviceClassName, iterable $cTypes): void + { + $componentRegistryEntry = new ComponentRegistryEntry($serviceClassName); + foreach ($cTypes as $cType) { + $componentRegistryEntry->addCType($cType); + } + $this->componentRegistryEntries[] = $componentRegistryEntry; + } + + /** + * @return iterable + */ + public function getComponentRegistryEntries(): iterable + { + return $this->componentRegistryEntries; + } +} diff --git a/Classes/ContainerBuilding/ComponentRegistryEntry.php b/Classes/ContainerBuilding/ComponentRegistryEntry.php new file mode 100644 index 0000000..64c735b --- /dev/null +++ b/Classes/ContainerBuilding/ComponentRegistryEntry.php @@ -0,0 +1,30 @@ + $cTypes + */ + private array $cTypes = []; + + public function __construct( + public readonly string $componentClassname, + ) {} + + public function addCType(string $cType): void + { + $this->cTypes[] = $cType; + } + + /** + * @return iterable + */ + public function getCTypes(): iterable + { + return $this->cTypes; + } +} diff --git a/Classes/ContainerBuilding/EventListener/AddComponentsToTypoScript.php b/Classes/ContainerBuilding/EventListener/AddComponentsToTypoScript.php new file mode 100644 index 0000000..089c092 --- /dev/null +++ b/Classes/ContainerBuilding/EventListener/AddComponentsToTypoScript.php @@ -0,0 +1,51 @@ +generateTypoScript()); + } + + public function __construct( + private readonly ComponentRegistry $componentRegistry, + ) {} + + private function generateTypoScript(): string + { + $typoScript = ''; + foreach ($this->componentRegistry->getComponentRegistryEntries() as $entry) { + $typoScript .= $this->generateTypoScriptForComponent($entry); + } + return $typoScript; + } + + private function generateTypoScriptForComponent(ComponentRegistryEntry $entry): string + { + $typoScript = ''; + foreach ($entry->getCTypes() as $cType) { + $typoScript .= $this->generateTypoScriptForCType($entry, $cType); + } + return $typoScript; + } + + private function generateTypoScriptForCType(ComponentRegistryEntry $entry, string $cType): string + { + return << +tt_content.{$cType} = WEBCOMPONENT +tt_content.{$cType}.component = {$entry->componentClassname} +TYPOSCRIPT; + } +} diff --git a/Configuration/Services.php b/Configuration/Services.php new file mode 100644 index 0000000..7dc3df7 --- /dev/null +++ b/Configuration/Services.php @@ -0,0 +1,21 @@ +registerAttributeForAutoconfiguration( + ComponentForContentElements::class, + static function (ChildDefinition $definition, ComponentForContentElements $attribute, \Reflector $reflector): void { + $definition->addTag( + ComponentForContentElements::TAG_NAME, + ['cType' => $attribute->cType] + ); + } + ); + + $containerBuilder->addCompilerPass(new ComponentPass(ComponentForContentElements::TAG_NAME)); +}; diff --git a/README.md b/README.md index ea3fbb9..772ffaf 100644 --- a/README.md +++ b/README.md @@ -28,20 +28,17 @@ Generates the output: You can populate the web component with PHP: -``` -tt_content.tx_myext_mycontentelement = WEBCOMPONENT -tt_content.tx_myext_mycontentelement.component = Acme\MyExt\Components\MyContentElement -``` - ```php