Skip to content

Commit

Permalink
Add AsTwigConstantAccessor attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
jdecool committed May 2, 2024
1 parent 0f26bfb commit 51ec0c7
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 5 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ services:
- { name: twig.constant_accessor, matches: '/^RULE_/' } # matches accept an regexp compatible with the preg_match function
```

Or you can use the `#[AsTwigConstantAccessor]` attribute on your class :

```php
use JDecool\Bundle\TwigConstantAccessorBundle\Annotation\AsTwigConstantAccessor;

#[AsTwigConstantAccessor]
class MyClass
{
// ...
}
```

After you can access your class constant in your templates :

```twig
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}
],
"require": {
"php": "^8.0",
"php": "^8.1",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/framework-bundle": "^5.4|^6.0|^7.0",
"symfony/twig-bundle": "^5.4|^6.0|^7.0",
Expand Down
13 changes: 13 additions & 0 deletions src/Attribute/AsTwigConstantAccessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace JDecool\Bundle\TwigConstantAccessorBundle\Attribute;

#[\Attribute(\Attribute::TARGET_CLASS)]
final class AsTwigConstantAccessor
{
public function __construct(
public readonly ?string $alias = null,
public readonly ?string $matches = null,
) {
}
}
20 changes: 20 additions & 0 deletions src/JDecoolTwigConstantAccessorBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

namespace JDecool\Bundle\TwigConstantAccessorBundle;

use JDecool\Bundle\TwigConstantAccessorBundle\Attribute\AsTwigConstantAccessor;
use JDecool\Bundle\TwigConstantAccessorBundle\DependencyInjection\Compiler\TwigConstantExtensionPass;
use JDecool\Bundle\TwigConstantAccessorBundle\DependencyInjection\Compiler\TwigConstantOptimizerPass;
use JDecool\Bundle\TwigConstantAccessorBundle\DependencyInjection\JDecoolTwigConstantAccessorExtension;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\HttpKernel\Bundle\Bundle;
Expand All @@ -15,6 +17,24 @@ public function build(ContainerBuilder $container): void
{
parent::build($container);

$container->registerAttributeForAutoconfiguration(
AsTwigConstantAccessor::class,
static function(ChildDefinition $definition, AsTwigConstantAccessor $attribute, \Reflector $reflector): void {
if (!$reflector instanceof \ReflectionClass) {
throw new \LogicException('AsTwigConstantAccessor attribute can only be used on classes.');
}

$definition->addTag(
'twig.constant_accessor',
[
'class' => $definition->getClass() ?? $reflector->getName(),
'alias' => $attribute->alias,
'matches' => $attribute->matches,
],
);
},
);

$container->addCompilerPass(new TwigConstantExtensionPass());
$container->addCompilerPass(new TwigConstantOptimizerPass());
}
Expand Down
12 changes: 12 additions & 0 deletions tests/Fixtures/Foo/ClassConstantByAttribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Foo;

use JDecool\Bundle\TwigConstantAccessorBundle\Attribute\AsTwigConstantAccessor;

#[AsTwigConstantAccessor]
class ClassConstantByAttribute
{
public const FOO = 'foo';
public const BAR = 'bar';
}
18 changes: 18 additions & 0 deletions tests/Fixtures/Foo/ClassConstantByAttributeWithArgs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Foo;

use JDecool\Bundle\TwigConstantAccessorBundle\Attribute\AsTwigConstantAccessor;

#[AsTwigConstantAccessor(
alias: 'WithAttribute',
matches: '/^SELECTED_/',
)]
class ClassConstantByAttributeWithArgs
{
public const FOO = 'foo';
public const BAR = 'bar';

public const SELECTED_FOO = 'selected_foo';
public const SELECTED_BAR = 'selected_bar';
}
6 changes: 6 additions & 0 deletions tests/Functionals/Resources/config/services.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
services:
_defaults:
autoconfigure: true

template:
alias: twig
public: true

Foo\ClassConstantByAttribute: ~
Foo\ClassConstantByAttributeWithArgs: ~

constant_by_service:
class: RegExp\Rules
tags:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{{ ClassConstantByAttribute.FOO }}
{{ ClassConstantByAttribute.BAR }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{{ WithAttribute.SELECTED_FOO }}
{{ WithAttribute.SELECTED_BAR }}
23 changes: 19 additions & 4 deletions tests/Functionals/TemplateKernelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,34 @@ public function testServiceMatchesConfiguration(): void
$this->assertStringNotContainsString('doe', $content);
}

/**
* @requires PHP >= 8.1
*/
public function testEnumAccess(): void
{
if (!class_exists(\UnitEnum::class)) {
$this->markTestSkipped('Enum class is not available');
}

$content = $this->render('enum.html.twig');

$this->assertStringNotContainsString('Foo', $content);
$this->assertStringContainsString('Bar', $content);
$this->assertStringContainsString('acme', $content);
}

public function testAccessByAttribute(): void
{
$content = $this->render('class_constants_by_attribute.html.twig');

$this->assertStringContainsString('foo', $content);
$this->assertStringContainsString('bar', $content);
}

public function testAccessByAttributeWithArgs(): void
{
$content = $this->render('class_constants_by_attribute_with_args.html.twig');

$this->assertStringContainsString('selected_foo', $content);
$this->assertStringContainsString('selected_bar', $content);
}

private function render(string $template): string
{
/** @var Environment $twig */
Expand Down

0 comments on commit 51ec0c7

Please sign in to comment.