Easily Share Your Twig Extensions with Symfony 6.1

Tac Tacelosky
4 min readMay 27, 2022

--

Symfony 6.1 is now out, and one of my favorite new features is a greatly simplified bundle configuration. Previously, setting up a simple bundle required a lot of files and writing XML by hand. In this article, I’ll show an how to set up a bundle with just THREE required files (LICENSE and README.md are automatically created but aren’t required).

https://github.com/survos/BarcodeBundle

In my case, and for this tutorial, I had a twig extension in an app and needed it somewhere else. Perfect for a bundle, but prior to Symfony 6.1 I didn’t think it was worth the effort to set up. I think most bundles are first developed in an application, then moved to a bundle once they’re working. One advantage to that approach is to leverage Symfony’s maker-bundle to create files, then selectively move them.

For this example, we’ll create a bundle that makes it easy to generate a SVG barcode from Twig. We’ll be able to set the barcode color and size when calling it, or set the color and size globally from a configuration file in our app.

The real work is of creating the barcode happens in the php library (https://github.com/picqer/php-barcode-generator), This is a common use case for a bundle — take an existing library and make it easy for Symfony developers to configure and use it.

First, run composer init, and make sure to select set the type to ‘symfony-bundle’ when prompted. There are 3 dependencies that a Symfony bundle needs, and our bundle also needs the barcode library. The final, minimal composer.json is short and sweet.

{
"name": "survos/barcode-bundle",
"description": "Integrates picqer/php-barcode-generator in a Symfony application",
"type": "symfony-bundle",
"license": "MIT",
"require": {
"php": "^8.1",
"picqer/php-barcode-generator": "^2.2",
"symfony/config": "^6.1",
"symfony/dependency-injection": "^6.1",
"symfony/http-kernel": "^6.1"
},
"autoload": {
"psr-4": {
"Survos\\BarcodeBundle\\": "src/"
}
}
}

First, I moved the twig extension I had created in my application (via bin/console make:twig BarcodeTwigExtension), and changed the namespace from App\Twig to Survos\BarcodeBundle\Twig.

The business logic is pretty simple, I want to generate a barcode from a twig filter or function, and use the values passed in or the defaults when generating the barcode. PHP 8’s constructor property promotion makes this very tight.

public function __construct(private int $widthFactor, 
private int $height,
private string $foregroundColor) {}
// wire the barcode filter / function to call: public function barcode(string $value, ?int $widthFactor = null, ?int $height = null, ?string $foregroundColor = null, string $type = BarcodeGenerator::TYPE_CODE_128): string
{
$generator = new BarcodeGeneratorSVG();
return $generator->getBarcode($value, $type,
$widthFactor ?? $this->widthFactor,
$height ?? $this->height,
$foregroundColor ?? $this->foregroundColor);
}

For the bundle configuration, we need to allow users to configure the colors and size via yaml, xml or php. Symfony takes care of all this, we just need to configure it in the bundle definition class. As the recommended naming convention is <org><name>Bundle, we’ll create SurvosBarcodeBundle.php in the src directory.

There are 2 steps — define the configuration in the configure method, then pass that information on to our twig extension class in the loadExtension method.

class SurvosBarcodeBundle extends AbstractBundle
{

protected string $extensionAlias = 'survos_barcode';
public function configure(DefinitionConfigurator $definition): void
{
// since the configuration is short, we can add it here
$definition->rootNode()
->children()
->scalarNode('widthFactor')->defaultValue(2)->end()
->scalarNode('height')->defaultValue(30)->end()
->scalarNode('foregroundColor')->defaultValue('green')->end()
->end();

;
}
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
{
$definition = $builder
->autowire('survos.barcode_twig', BarcodeTwigExtension::class)
->addTag('twig.extension');

$definition->setArgument('$widthFactor', $config['widthFactor']);
$definition->setArgument('$height', $config['height']);
$definition->setArgument('$foregroundColor', $config['foregroundColor']);
}
}

The configure is trivial, define the 3 keys we want. Loading the extension can now be done without XML files, the autocomplete and type checking makes it much easier set up. In this case, we want to autowire the twig extension and add the twig.extension tag, so it’s available to our app. Then we pass the 3 properties we got from the config to the extension constructor.

That’s it. Let’s see it in action.

symfony new BarcodeDemo --webapp && cd BarcodeDemo
yarn install
bin/console make:controller AppController
composer req survos/barcode-bundle
echo "{{ 'test'|barcode }} or {{ barcode('test', 2, 80, 'red') }} " > templates/app/index.html.twig
symfony server:start -d

Then open https://127.0.0.1:8000/app

I’m quite enthusiastic about how much easier it is to set up bundles. The next thing I’d like to do is set up a UX bundle that includes stimulus controllers, which I think can totally change front end development for Symfony developers.

--

--