Skip to content

Commit

Permalink
[TwigHooks][Maintenance] Split the BaseHookable into the HookableComp…
Browse files Browse the repository at this point in the history
…onent and HookableTemplate (#6)

Previously we've been diversifying hookables by a string. From now, we
have more flexibility since we can add a custom fields (like `props` for
the hookable component) :).
  • Loading branch information
jakubtobiasz authored Apr 23, 2024
2 parents fc6b05f + 58304ab commit c4fb80f
Show file tree
Hide file tree
Showing 47 changed files with 818 additions and 470 deletions.
2 changes: 2 additions & 0 deletions src/TwigHooks/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
"laminas/laminas-stdlib": "^3.18",
"symfony/config": "^5.4 || ^6.0",
"symfony/dependency-injection": "^5.4 || ^6.0",
"symfony/expression-language": "^5.4 || ^6.0",
"symfony/http-kernel": "^5.4 || ^6.0",
"symfony/stopwatch": "^5.4 || ^6.0",
"symfony/ux-twig-component": "^2.12",
"symfony/twig-bundle": "^5.4 || ^6.0",
"twig/twig": "^2.15 || ^3.0"
},
"require-dev": {
Expand Down
4 changes: 2 additions & 2 deletions src/TwigHooks/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Sylius\TwigHooks\Hook\NameGenerator\TemplateNameGenerator;
use Sylius\TwigHooks\Provider\ComponentContextProvider;
use Sylius\TwigHooks\Provider\ComponentPropsProvider;
use Sylius\TwigHooks\Provider\DefaultConfigurationProvider;
use Sylius\TwigHooks\Provider\DefaultContextProvider;
use Sylius\TwigHooks\Registry\HookablesRegistry;
Expand All @@ -18,7 +18,7 @@

$services->set('twig_hooks.provider.default_context', DefaultContextProvider::class);

$services->set('twig_hooks.provider.component_data', ComponentContextProvider::class)
$services->set('twig_hooks.provider.component_props', ComponentPropsProvider::class)
->args([
inline_service(ExpressionLanguage::class),
])
Expand Down
1 change: 1 addition & 0 deletions src/TwigHooks/config/services/hookable_renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

$services->set('twig_hooks.renderer.hookable.component', HookableComponentRenderer::class)
->args([
service('twig_hooks.provider.component_props'),
service('ux.twig_component.component_renderer'),
])
->tag('twig_hooks.hookable_renderer')
Expand Down
31 changes: 22 additions & 9 deletions src/TwigHooks/src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

namespace Sylius\TwigHooks\DependencyInjection;

use Sylius\TwigHooks\Hookable\BaseHookable;
use Sylius\TwigHooks\Hookable\HookableComponent;
use Sylius\TwigHooks\Hookable\HookableTemplate;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
Expand All @@ -30,8 +31,8 @@ private function addSupportedHookableTypesConfiguration(ArrayNodeDefinition $roo
->arrayNode('supported_hookable_types')
->useAttributeAsKey('type')
->defaultValue([
'template' => BaseHookable::class,
'component' => BaseHookable::class,
'template' => HookableTemplate::class,
'component' => HookableComponent::class,
])
->scalarPrototype()->end()
->end()
Expand All @@ -44,9 +45,9 @@ private function addHooksConfiguration(ArrayNodeDefinition $rootNode): void
$rootNode
->children()
->arrayNode('hooks')
->useAttributeAsKey('name')
->useAttributeAsKey('_name')
->arrayPrototype()
->useAttributeAsKey('name')
->useAttributeAsKey('_name')
->arrayPrototype()
->beforeNormalization()
->always(function ($v) {
Expand All @@ -64,21 +65,33 @@ private function addHooksConfiguration(ArrayNodeDefinition $rootNode): void
})
->end()
->validate()
->ifTrue(function ($v) {
->always(static function ($v) {
$component = $v['component'] ?? null;
$template = $v['template'] ?? null;

return null !== $component && null !== $template;
if (null !== $component && null !== $template) {
throw new \InvalidArgumentException('You cannot define both "component" and "template" at the same time.');
}

if (null === $component && [] !== $v['props']) {
throw new \InvalidArgumentException('"Props" cannot be defined for non-component hookables.');
}

return $v;
})
->thenInvalid('You cannot define both "component" and "template" at the same time.')
->end()
->canBeDisabled()
->children()
->scalarNode('type')->defaultValue('template')->end()
->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
->scalarNode('component')->defaultNull()->end()
->scalarNode('template')->defaultNull()->end()
->arrayNode('data')
->arrayNode('context')
->defaultValue([])
->useAttributeAsKey('name')
->prototype('variable')->end()
->end()
->arrayNode('props')
->defaultValue([])
->useAttributeAsKey('name')
->prototype('variable')->end()
Expand Down
68 changes: 63 additions & 5 deletions src/TwigHooks/src/DependencyInjection/TwigHooksExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace Sylius\TwigHooks\DependencyInjection;

use Sylius\TwigHooks\Hookable\HookableComponent;
use Sylius\TwigHooks\Hookable\HookableTemplate;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
Expand All @@ -30,7 +32,7 @@ public function load(array $configs, ContainerBuilder $container): void
* @param array<string, array<string, array{
* type: string,
* target: string,
* data: array<string, mixed>,
* context: array<string, mixed>,
* configuration: array<string, mixed>,
* priority: int,
* enabled: bool,
Expand Down Expand Up @@ -60,7 +62,8 @@ private function registerHooks(ContainerBuilder $container, array $hooks, array
* @param array{
* type: string,
* target: string,
* data: array<string, mixed>,
* props?: array<string, mixed>,
* context: array<string, mixed>,
* configuration: array<string, mixed>,
* priority: int,
* enabled: bool,
Expand All @@ -72,15 +75,70 @@ private function registerHookable(
string $hookName,
string $hookableName,
array $hookable,
): void {
match ($class) {
HookableTemplate::class => $this->registerTemplateHookable($container, $hookName, $hookableName, $hookable),
HookableComponent::class => $this->registerComponentHookable($container, $hookName, $hookableName, $hookable),
default => throw new \InvalidArgumentException(sprintf('Unsupported hookable class "%s".', $class)),
};
}

/**
* @param array{
* type: string,
* target: string,
* context: array<string, mixed>,
* configuration: array<string, mixed>,
* priority: int,
* enabled: bool,
* } $hookable
*/
private function registerTemplateHookable(
ContainerBuilder $container,
string $hookName,
string $hookableName,
array $hookable,
): void {
$container
->register(sprintf('twig_hooks.hook.%s.hookable.%s', $hookName, $hookableName), HookableTemplate::class)
->setArguments([
$hookName,
$hookableName,
$hookable['target'],
$hookable['context'],
$hookable['configuration'],
$hookable['priority'],
$hookable['enabled'],
])
->addTag('twig_hooks.hookable', ['priority' => $hookable['priority']])
;
}

/**
* @param array{
* type: string,
* target: string,
* props?: array<string, mixed>,
* context: array<string, mixed>,
* configuration: array<string, mixed>,
* priority: int,
* enabled: bool,
* } $hookable
*/
private function registerComponentHookable(
ContainerBuilder $container,
string $hookName,
string $hookableName,
array $hookable,
): void {
$container
->register(sprintf('twig_hooks.hook.%s.hookable.%s', $hookName, $hookableName), $class)
->register(sprintf('twig_hooks.hook.%s.hookable.%s', $hookName, $hookableName), HookableComponent::class)
->setArguments([
$hookName,
$hookableName,
$hookable['type'],
$hookable['target'],
$hookable['data'],
$hookable['props'] ?? [],
$hookable['context'],
$hookable['configuration'],
$hookable['priority'],
$hookable['enabled'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

final class HookDebugCommentRenderer implements HookRendererInterface
{
public function __construct(private HookRendererInterface $innerRenderer)
public function __construct(private readonly HookRendererInterface $innerRenderer)
{
}

Expand Down
2 changes: 1 addition & 1 deletion src/TwigHooks/src/Hook/Renderer/HookRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function render(array $hookNames, array $hookContext = []): string
$renderedHookables = [];

foreach ($hookables as $hookable) {
$hookMetadata = new HookMetadata($hookable->getHookName(), new ParameterBag($hookContext));
$hookMetadata = new HookMetadata($hookable->hookName, new ParameterBag($hookContext));

$context = $this->contextProvider->provide($hookable, $hookContext);
$configuration = $this->configurationProvider->provide($hookable);
Expand Down
86 changes: 10 additions & 76 deletions src/TwigHooks/src/Hookable/AbstractHookable.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,78 +8,26 @@ abstract class AbstractHookable
{
public const DEFAULT_PRIORITY = 0;

public const TYPE_COMPONENT = 'component';

public const TYPE_TEMPLATE = 'template';

/**
* @param array<string, mixed> $data
* @param array<string, mixed> $context
* @param array<string, mixed> $configuration
*/
public function __construct (
protected string $hookName,
protected string $name,
protected string $type,
protected string $target,
protected array $data = [],
protected array $configuration = [],
protected ?int $priority = null,
protected ?bool $enabled = null,
public readonly string $hookName,
public readonly string $name,
public readonly string $target,
public readonly array $context = [],
public readonly array $configuration = [],
protected readonly ?int $priority = null,
protected readonly ?bool $enabled = null,
) {
}

public function getHookName(): string
{
return $this->hookName;
}

public function getName(): string
{
return $this->name;
}

public function getType(): string
{
return $this->type;
}

public function isType(string $type): bool
{
return $this->type === $type;
}

public function isComponentType(): bool
{
return $this->isType(self::TYPE_COMPONENT);
}

public function isTemplateType(): bool
{
return $this->isType(self::TYPE_TEMPLATE);
}

public function getId(): string
{
return sprintf('%s#%s', $this->hookName, $this->name);
}

public function getTarget(): string
{
return $this->target;
}

/** @return array<string, mixed> */
public function getData(): array
{
return $this->data ?? [];
}

/** @return array<string, mixed> */
public function getConfiguration(): array
{
return $this->configuration ?? [];
}

public function getPriority(): int
{
return $this->priority ?? self::DEFAULT_PRIORITY;
Expand All @@ -90,21 +38,7 @@ public function isEnabled(): bool
return $this->enabled ?? true;
}

public function overwriteWith(self $hookable): self
{
if ($hookable->getName() !== $this->getName()) {
throw new \InvalidArgumentException('Hookable cannot be overwritten with different name.');
}
abstract public function overwriteWith(self $hookable): self;

return new static(
$hookable->getHookName(),
$hookable->getName(),
$hookable->getType(),
$hookable->getTarget(),
array_merge($this->getData(), $hookable->data),
array_merge($this->getConfiguration(), $hookable->configuration),
$hookable->priority ?? $this->getPriority(),
$hookable->enabled ?? $this->isEnabled(),
);
}
abstract public function getType(): string;
}
9 changes: 0 additions & 9 deletions src/TwigHooks/src/Hookable/BaseHookable.php

This file was deleted.

Loading

0 comments on commit c4fb80f

Please sign in to comment.