5

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="" /> 

5 Answers 5

17

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

Sign up to request clarification or add additional context in comments.

10 Comments

What should I inject in config.yml ? "@what" ?
The service id is "templating.helper.assets". So @templating.helper.assets should do it
It will complain about the scope if you try to inject templating.helper.assets
ah, I see, you will have to add scope: request to your service definition. Alternatively, you can inject the container itself and then calling $this->container->get('templating.helper.assets') should also work.
Yes, I did inject the container "@service_container" and I used $this->container->get('templating.helper.assets') . Thanks.
|
7

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.

2 Comments

Thank you for this. I much prefer this method over injecting the container
This will trigger a deprecation warning nowadays which can be fixed by implementing the Twig_Extension_InitRuntimeInterface or reworking the code with injection of the Twig_Environment: twig.sensiolabs.org/doc/advanced.html#environment-aware-filters
3

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');

Comments

1

In Symfony 5.3 that worked for me: (just do what the assets extension does and inject Packages)


use Symfony\Component\Asset\Packages;
use Twig\Extension\AbstractExtension;
use Twig\Extension\ExtensionInterface;

class AppExtension extends AbstractExtension implements ExtensionInterface
{
    public function __construct(Packages $packages)
    {
        $this->packages = $packages;
    }

    // ... your other methods

    private function asset($path, $packageName = null)
    {
        return $this->packages->getUrl($path, $packageName);
    }
}

Comments

0

In Symfony 2.8 that works for me:

# services.yml
services:
    app.twig_extension:
        class: AppBundle\Twig\AppTwigExtension
        public: false
        arguments:
            - @templating.helper.assets
        tags:
            - { name: twig.extension }

AppTwigExtension class:

namespace AppBundle\Twig;

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

/**
 * Class AppTwigExtension
 * @package AppBundle\Twig
 */
class AppTwigExtension extends \Twig_Extension
{
    const IMG_PATH = 'bundles/app/images/';

    private $assetsHelper;

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

    public function getFilters()
    {
        return array(
            new \Twig_SimpleFilter('img', array($this, 'imagePathFilter'))
        );
    }

    /**
     * Get image path relatively to host
     * Usage in Twig template: {{ 'my_image.png'|img }} - equal to
     * {{ asset('bundles/app/images/my_image.png') }} in Twig template:
     *
     * @param string $imageName (e.g. my_image.png)
     * @return string
     */
    public function imagePathFilter($imageName)
    {
        return $this->assetsHelper->getUrl(self::IMG_PATH . $imageName);
    }

    public function getName()
    {
        return 'app_twig_extension';
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.