Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony, How to generate Asset URL in a Twig Extension class?

Tags:

twig

symfony

I have one class which extends \Twig_Extension like below :

class MYTwigExtension extends \Twig_Extension
{

    protected $doctrine;

    protected $router;


    public function __construct(RegistryInterface $doctrine , $router)
    {
        $this->doctrine = $doctrine;
        $this->router = $router;

    }

    public function auth_links($user , $request)
    {
       // Some other codes here ...

       // HOW TO GENERATE $iconlink which is like '/path/to/an/image'

       $html .= "<img src=\"$iconlink\" alt=\"\" />  ";  

       echo $html;
    }

}

My question is How to generate Asset links in a Twig Extension ? I would like a replacement for ASSET helper in my class. Bassically I have no idea what I have to inject or use here ! Thanks in advance.

 <img src="{{ asset('img/icons/modules/timesheet.png') }}" alt="" /> 
like image 910
pmoubed Avatar asked Jun 14 '12 17:06

pmoubed


3 Answers

You can use the templating.helper.assets service directly.

use Symfony\Component\DependencyInjection\ContainerInterface;

public function __construct(ContainerInterface $container)
{
    $this->container = $container;
}

and use it like so:

$this->container->get('templating.helper.assets')->getUrl($iconlink);

Injecting just the templating.helper.assets directly does not work in this case because the twig extension cannot be in the request scope. See the documentation here: https://symfony.com/doc/2.3/cookbook/service_container/scopes.html#using-a-service-from-a-narrower-scope

like image 122
MDrollette Avatar answered Oct 14 '22 00:10

MDrollette


I didn't want to deal with the Dependency Injection Container. This is what I did:

use Twig_Environment as Environment;

class MyTwigExtension extends \Twig_Extension
{
    protected $twig;
    protected $assetFunction;

    public function initRuntime(Environment $twig)
    {
        $this->twig = $twig;
    }

    protected function asset($asset)
    {
        if (empty($this->assetFunction)) {
             $this->assetFunction = $this->twig->getFunction('asset')->getCallable();
        }
        return call_user_func($this->assetFunction, $asset);
    }

I've looked at Twig_Extension class code, and found this initRuntime method there, to be overriden in our custom Extension class. It receives the Twig_Environment as an argument! This object has a getFunction method, which returns a Twig_Function instance. We only need to pass the function name (asset, in our case).

The Twig_Function object has a getCallable method, so we finally can have a callable asset function.

I've gone a bit further creating an asset method for my own extension class. Anywhere else on it, I can simply call $this->asset() and obtain the same result as {{ asset() }} in the templates.

EDIT: The getFunction call at initRuntime throws a scope exception when clearing the cache. So I moved it to the custom asset method. It works fine.

like image 23
J. Bruni Avatar answered Oct 13 '22 23:10

J. Bruni


Here's a simple and clean way for Symfony 2.8:

services.yml:

app.twig_extension:
    class: Path\To\AcmeExtension
    arguments:
        assets: "@templating.helper.assets"

In the TWIG extension:

use Symfony\Bundle\FrameworkBundle\Templating\Helper\AssetsHelper;

class AcmeExtension
{
    protected $assets;

    public function __construct(AssetsHelper $assets)
    {
        $this->assets = $assets;
    }
}

Then you can use it in any function of the extension like this:

$this->assets->getUrl('myurl');
like image 44
Thomas Landauer Avatar answered Oct 14 '22 00:10

Thomas Landauer