45

is there a way to check if twig template exists before calling to render? A try catch block seems not to work, at least in dev environment, and plus, I prefer a check than the cost of an exception.

This class TwigEngine has an exists() method, but didn't find examples on use.

dreftymac
  • 31,404
  • 26
  • 119
  • 182
K. Weber
  • 2,643
  • 5
  • 45
  • 77

6 Answers6

68

The service holding the twig engine if configured as default is 'templating'.

Inside your Controller do the following:

if ( $this->get('templating')->exists('AcmeDemoBundle:Foo:bar.html.twig') ) {
     // ...
}

The alternative would be catching exception the render() method throws like this:

 try {
      $this->get('templating')->render('AcmeDemoBundle:Foo:bar.html.twig')
  } catch (\Exception $ex) {
     // your conditional code here.
  }

In a normal controller ...

$this->render('...')

is only an alias for ...

$this->container->get('templating')->renderResponse($view, $parameters, $response);

... while ...

$this->get('...') 

... is an alias for

$this->container->get('...')

Have a look at Symfony\FrameworkBundle\Controller\Controller.

Nicolai Fröhlich
  • 51,330
  • 11
  • 126
  • 130
  • 1
    This is no longer the recommended answer, please check javiers answer below. – Anyone Jun 24 '19 at 15:04
  • This works for Symfony 3.4.* `$this->container->get('templating')->exists('@YourBundle/..Path../twigName.html.twig')` if there is not `$this->container` use `$this->getContainer()->...` instead. – ali6p Sep 23 '20 at 22:16
40

The templating service will be removed in future Symfony versions. The future-proof solution based on the twig service is:

if ($this->get('twig')->getLoader()->exists('AcmeDemoBundle:Foo:bar.html.twig')) {
    // ...
}
Javier Eguiluz
  • 3,987
  • 2
  • 23
  • 44
  • Do you have any reference to support your statement that the `templating` service will be removed in future Symfony versions? – dezlov May 17 '18 at 06:46
  • 5
    It should be reference enouhh that Javier is working for SensioLabs ;) – Nico Haase Feb 01 '19 at 16:37
  • 2
    An announcement about deprecating templating: https://symfony.com/blog/new-in-symfony-4-3-deprecated-the-templating-component-integration – rrehbein Jun 03 '19 at 20:04
28

In case you need to check for template existance from inside twig templates you have to use the array include methods, as described in the documentation:

{% include ['page_detailed.html', 'page.html'] %}
silzenna
  • 311
  • 3
  • 2
  • 2
    This is pretty handy on the template end. Can have an empty template to safely do nothing when tempate is not there ```{% include ['page_detailed.html', 'page.html', 'empty-catch-all.html'] %}``` – yuvilio Apr 22 '15 at 15:00
  • Is there a way to include the template if already not exists only ? – Radhakrishna Dec 19 '16 at 05:11
24

Maybe also an option:

{% include 'AcmeDemoBundle:Foo:bar.html.twig' ignore missing %}

The ignore missing addition tells twig to simply do nothing, when the template is not found.

Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100
  • 1
    I can't imagine a situation where this would be useful, but it's still a very interesting thing to know of. – aalaap Dec 27 '16 at 13:04
  • it is in cases of dynamically loaded templates. Like if you want to include a specific template by a given name and this template with that name doesnt exist and you don't want a 500 come up than this is a possible option –  Jan 04 '17 at 09:59
  • Thanks - using this to load in templates dynamically as per comment above. – Michael Apr 13 '17 at 12:38
2

You can do it this way using dependency injection:

use Symfony\Component\Templating\EngineInterface;

public function fooAction(EngineInterface $templeEngine)
{
    if ($templeEngine->exists("@App/bar/foo.html.twig")) {
        // ...
    }
    // ...
}

Tested with Symfony 3.4.

Mateusz
  • 2,340
  • 25
  • 24
  • 1
    in the way i have seen with latest flex you dont need the @App reference, if the templates are in their default location just the relative path is enough ie i have templates/Email/campaign.html.twig and @App/Email/campaign.html.twig does not work just Email/campaign.html.twig works – Bizmate Jan 23 '19 at 12:14
2

You can use dependency injection to get the Environment that stores the Twig configuration. Like this (in controller):

/**
 * @Route("/{path}")
 */
public function index($path, Twig\Environment $env)
{
    if (!$env->getLoader()->exists('pages/'.$path.'.html.twig')) {
        return $this->render('pages/404.html.twig');
    }
}
Taylan
  • 3,045
  • 3
  • 28
  • 38
Ghazaleh Javaheri
  • 1,829
  • 19
  • 25