Skip to content

Commit

Permalink
Decouple label building from Twig extension (#138)
Browse files Browse the repository at this point in the history
It can be reused from PHP
  • Loading branch information
laurent-bientz authored Mar 22, 2020
1 parent 0efe20b commit ccd86f4
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 33 deletions.
49 changes: 48 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,50 @@ final class MyEnum extends AbstractEnum
}
```

### Get label from a service

If you want to get the constant label behind an enum value, you can instantiate
the `GetLabel` class and invoke it.

```php
use Greg0ire\Enum\Bridge\Symfony\Translator\GetLabel;

$label = new GetLabel();
$label($value, 'Your\Enum\Class');
```

To enable translation, require the `symfony/translation` component
and pass a `Symfony\Contracts\Translation\TranslationInterface` instance on the
`GetLabel` constructor

```php
use Greg0ire\Enum\Bridge\Symfony\Translator\GetLabel;
use Symfony\Contracts\Translation\TranslationInterface;

$label = new GetLabel($translator);
$label($value, 'Your\Enum\Class');
```

If you're using Symfony, tag the service and simply inject it.
If translations are enabled, the `TranslatorInterface` will be automatically injected.

```yaml
services:
# ...
Greg0ire\Enum\Bridge\Symfony\Translator\Label: "@greg0ire_enum.symfony.translator.label"
```
```php
public function index(GetLabel $label)
{
$label($value, 'Your\Enum\Class');
$label($value, 'Your\Enum\Class', 'another_domain'); // Change the translation domain
$label($value, 'Your\Enum\Class', false); // Disable translation. In this case the class prefix wont be added
$label($value, 'Your\Enum\Class', false, true); // Disable translation but keep class prefix
$label($value, 'Your\Enum\Class', false, true, '.'); // Disable translation but keep class prefix with a custom separator
}
```

### Integration with other libraries

`greg0ire/enum` integrates with other libraries. The list is available in the
Expand Down Expand Up @@ -230,8 +274,11 @@ You have to require the `twig/twig` package to get it working.

The `enum_label` filter will try to return the constant label corresponding to the given value.

This filter relies on the `Greg0ire\Enum\Bridge\Symfony\Translator\GetLabel` service.

It will try to translate it if possible. To enable translation, require the `symfony/translation` component
and pass a `Symfony\Contracts\Translation\TranslationInterface` instance on the `EnumExtension` constructor.
and pass a `Symfony\Contracts\Translation\TranslationInterface` instance on the `GetLabel` constructor.
`GetLabel` instance will be injected on the `EnumExtension` constructor.

If translation is not available, you will have the default label with class prefixing.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class TranslatorCompilerPass implements CompilerPassInterface
public function process(ContainerBuilder $container): void
{
if (class_exists(AbstractExtension::class) && $container->hasDefinition('translator.default')) {
$container->getDefinition('greg0ire_enum.twig.extension.enum')
$container->getDefinition('greg0ire_enum.symfony.translator.label')
->addArgument(new Reference('translator.default'));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ public function load(array $configs, ContainerBuilder $container): void
if (class_exists(AbstractExtension::class)) {
$loader->load('twig.xml');
}

$loader->load('services.xml');
}
}
14 changes: 14 additions & 0 deletions src/Bridge/Symfony/Resources/config/services.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<defaults public="false" />

<service id="greg0ire_enum.symfony.translator.label" class="Greg0ire\Enum\Bridge\Symfony\Translator\Label" public="true">
<argument type="service" id="translator.default" />
</service>

</services>
</container>
62 changes: 62 additions & 0 deletions src/Bridge/Symfony/Translator/GetLabel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace Greg0ire\Enum\Bridge\Symfony\Translator;

use Symfony\Contracts\Translation\TranslatorInterface;

final class GetLabel
{
/**
* @var TranslatorInterface
*/
private $translator;

public function __construct(TranslatorInterface $translator = null)
{
$this->translator = $translator;
}

/**
* Displays the label corresponding to a specific value of an enumeration.
*
* @param mixed $value Must exists in the enumeration class specified with $class
* @param string $class The enum class name
* @param string|bool $translationDomain the translation domain to use if the translator if available.
* string: Use the specified one
* null: Use the default one
* false: Do not use the translator
* @param bool $classPrefixed Prefix the label with the enum class. Defaults to true if the translator
* is available and enabled, false otherwise.
* @param string $namespaceSeparator namespace separator to use with the class prefix.
* This takes effect only if $classPrefixed is true
*/
public function __invoke(
$value,
string $class,
$translationDomain = null,
?bool $classPrefixed = null,
?string $namespaceSeparator = null
): string {
// Determine if the translator can be used or not.
$useTranslation = $this->translator instanceof TranslatorInterface
&& (is_null($translationDomain) || is_string($translationDomain));

// If not defined, guess the default behavior.
if (is_null($classPrefixed)) {
$classPrefixed = $useTranslation;
}

$label = array_search(
$value,
call_user_func([$class, 'getConstants'], 'strtolower', $classPrefixed, $namespaceSeparator)
);

if ($useTranslation) {
$translatedLabel = $this->translator->trans($label, [], $translationDomain);

return $translatedLabel ?: $label;
}

return $label;
}
}
45 changes: 17 additions & 28 deletions src/Bridge/Twig/Extension/EnumExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Greg0ire\Enum\Bridge\Twig\Extension;

use Greg0ire\Enum\AbstractEnum;
use Greg0ire\Enum\Bridge\Symfony\Translator\GetLabel;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
Expand All @@ -14,16 +15,24 @@
final class EnumExtension extends AbstractExtension
{
/**
* @var TranslatorInterface
* @var GetLabel
*/
private $translator;
private $label;

/**
* @param TranslatorInterface $translator
*/
public function __construct(TranslatorInterface $translator = null)
public function __construct($label)
{
$this->translator = $translator;
if ($label instanceof TranslatorInterface) {
@trigger_error(sprintf(
'Providing a %s instance to %s is deprecated and will not be supported in 5.0. Please provide a %s instance instead.',
TranslatorInterface::class,
__METHOD__,
GetLabel::class
), E_USER_DEPRECATED);
$this->label = new GetLabel($label);

return;
}
$this->label = $label;
}

/**
Expand Down Expand Up @@ -67,27 +76,7 @@ public function label(
?bool $classPrefixed = null,
?string $namespaceSeparator = null
): string {
// Determine if the translator can be used or not.
$useTranslation = $this->translator instanceof TranslatorInterface
&& (is_null($translationDomain) || is_string($translationDomain));

// If not defined, guess the default behavior.
if (is_null($classPrefixed)) {
$classPrefixed = $useTranslation;
}

$label = array_search(
$value,
call_user_func([$class, 'getConstants'], 'strtolower', $classPrefixed, $namespaceSeparator)
);

if ($useTranslation) {
$translatedLabel = $this->translator->trans($label, [], $translationDomain);

return $translatedLabel ?: $label;
}

return $label;
return ($this->label)($value, $class, $translationDomain, $classPrefixed, $namespaceSeparator);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function testLoadWithoutATranslator()
);
}

public function testTwigExtensionHasTheTranslator()
public function testLabelServiceHasTheTranslator()
{
$this->registerService('translator.logging.inner', \stdClass::class);
$this->registerService('logger', \stdClass::class);
Expand All @@ -74,7 +74,7 @@ public function testTwigExtensionHasTheTranslator()
$compilerPass->process($this->container);

$this->assertContainerBuilderHasServiceDefinitionWithArgument(
'greg0ire_enum.twig.extension.enum',
'greg0ire_enum.symfony.translator.label',
0,
new Reference('translator.default')
);
Expand Down
3 changes: 2 additions & 1 deletion tests/Bridge/Twig/Extension/EnumExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Greg0ire\Enum\Tests\Bridge\Twig\Extension;

use Greg0ire\Enum\Bridge\Symfony\Translator\GetLabel;
use Greg0ire\Enum\Bridge\Twig\Extension\EnumExtension;
use Greg0ire\Enum\Tests\Fixtures\FooEnum;
use Greg0ire\Enum\Tests\Fixtures\FooInterface;
Expand Down Expand Up @@ -32,7 +33,7 @@ final class EnumExtensionTest extends TestCase
protected function setUp(): void
{
$this->translator = $this->createMock(TranslatorInterface::class);
$this->extension = new EnumExtension($this->translator);
$this->extension = new EnumExtension(new GetLabel($this->translator));
}

public function testEnvironment()
Expand Down

0 comments on commit ccd86f4

Please sign in to comment.