How to render a Twig View inside a command in Symfony 5

Twig is without a doubt one of the best templating engines for PHP that you can find nowadays. It comes included in a standard environment of Symfony 5 and can be used everywhere, however in the official documentation is quite difficult to identify an useful example of how to use the template engine outside of controllers, specifically inside a command. Commands are created with the specifical purpose of run memory intensive tasks that shouldn't run through a request on the browser, for example mass email sender services.

The most tipical usage of the templating engine inside a command, is to render the email template dinamically. In this article, we will explain you how to request the templating engine service inside a symfony command or to work with an isolated Twig environment.

A. Using the project's environment

By default, you will probably want to stick with the alreday configured Twig environment in your project, so you will have access to the routing methods ({{ path("some_route") }}) and app variable in the view. This is the easiest way to proceed as well compared to the option of an isolated environment, you will need simply to import the Twig\Environment namespace and inject the class in the constructor, exposing it to the class through a private variable. Then you will be able to call the render method from the $this->twig variable in the class as shown in the following example:

<?php

// src/Command/MyCommand.php
namespace App\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

// Import the Twig Environment
use Twig\Environment;

class MyCommand extends Command
{
    // the name of the command (the part after "bin/console")
    protected static $defaultName = 'app:my-command';
    
    // Create a private variable to store the twig environment
    private $twig;

    public function __construct(Environment $twig)
    {
        // Inject it in the constructor and update the value on the class
        $this->twig = $twig;

        parent::__construct();
    }
    
    protected function configure(){}

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // Render some template inside the project/templates/emails/example.html.twig
        $html = $this->twig->render('emails/example.html.twig', [
            'someVariable' => 123
        ]);

        // Preview HTML in the terminal
        $output->writeln($html);
        
        return 0;
    }
}

B. Using an isolated environment

Now if you want to work with a totally new Twig environment, you will need to follow some extra steps. You need to consider that working with this option, as mentioned, is like working with a Twig environment that has nothing to do with your project itself as you won't have access to the routing etc. As first, create a Service namely Twig that will load with the root directory of your project:

<?php
// src/Service/Twig.php
namespace App\Service;

use Symfony\Component\HttpKernel\KernelInterface;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

class Twig extends Environment {
    
    public function __construct(KernelInterface $kernel) {
        $loader = new FilesystemLoader("templates", $kernel->getProjectDir());
        
        parent::__construct($loader);
    }
}

Then, we will inject this service in the command through the constructor and unlike the first option, instead of rendering the template directly from the twig environment, it's necessary to load first the template and then call the render method, providing the parameters directly as first argument (if any):

<?php

// src/Command/MyCommand.php
namespace App\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

// Import the Twig Environment from the created service
use App\Service\Twig;

class MyCommand extends Command
{
    // the name of the command (the part after "bin/console")
    protected static $defaultName = 'app:my-command';
    
    // Create a private variable to store the twig environment
    private $twig;

    public function __construct(Twig $twig)
    {
        // Inject it in the constructor and update the value on the class
        $this->twig = $twig;

        parent::__construct();
    }
    
    protected function configure(){}

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // Load Twig File
        $template = $this->twig->load('emails/example.html.twig');

        // Render HTML
        $html = $template->render([
            'someVariable' => 123
        ]);

        // Preview HTML in the terminal
        $output->writeln($html);
        
        return 0;
    }
}

Happy coding ❤️!

This could interest you

Become a more social person