Symfony dependency injection in twig extension

纵然是瞬间 提交于 2020-01-04 14:27:17

问题


Ok, I was trying to create twig extension with dependencies on other service (security.context) and got some troubles. So, here is my service declaration:

acme.twig.user_extension:
        class: Acme\BaseBundle\Twig\UserExtension
        arguments: ["@security.context"]
        tags:
            - { name: twig.extension }

and here's my class

// acme/basebundle/twig/userextension.php

namespace Acme\BaseBundle\Twig;

use Symfony\Component\Security\Core\SecurityContext;
use Acme\UserBundle\Entity\User;

class UserExtension extends \Twig_Extension
{

    protected $context;

    public function __construct(SecurityContext $context){
        $this->context = $context;
    }

    public function getFunctions()
    {
        return array(
            'getAbcData' => new \Twig_SimpleFunction('getAbcData', $this->getAbcData()),
        );
    }

    public function getAbcData()
    {
        if ( !is_object($user = $this->context->getToken()->getUser()) || !$user instanceof User){ return null; }
        return array(
            'data_array'   => $user->getData(),
        );
    }

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

Finally, I have an error:

FatalErrorException: Error: Call to a member function getUser() on a non-object in \src\Acme\BaseBundle\Twig\UserExtension.php line 27

I guess that security.context service is not initialized yet, then i get an error. Could anyone tell, please, is there are ways to load service manually, or any better solutions for an issue? Thanks a lot.


I use Symfony 2.5.*

UPD:

I've also found this notice in symfony docs

Keep in mind that Twig Extensions are not lazily loaded. This means that there's a higher chance that you'll get a CircularReferenceException or a ScopeWideningInjectionException if any services (or your Twig Extension in this case) are dependent on the request service. For more information take a look at How to Work with Scopes. Actually, I have no idea about how to do it correct..


回答1:


You are calling $this->getAbcData() when constructing Twig_SimpleFilter. But you have to pass a callable as argument.

public function getFunctions() {
    return array (
        'getAbcData' => new \Twig_SimpleFunction( 'getAbcData', array( $this, 'getAbcData' ))
    );
}

Leo is also right. You should check first if getToken() is returning an object before trying getToken()->getUser().

You can also pass the user to the function as a parameter in twig: {{ getAbcData(app.user) }}. This way the function is more generic and could be used for any user, not just the currently logged in one.




回答2:


This should probably work. The error message means that getToken() is not an object so you have to test if getToken() is an object before testing if getUser() is also is an object.

public function getAbcData()
{
    $token = $this->context->getToken();

    if (!is_object($token) || !is_object($token->getUser())) {
        return null;
    }

    return array(
        'data_array'   => $user->getData(),
    );
}



回答3:


You need to change your twig extension to have the container not the security context passed into the constructor.

Twig_Extensions are special in that the normal rule of don't pass in the container but instead pass in only what you need often doesn't apply as it causes problems due to scope issues.

So change your extension to be like this.

// acme/basebundle/twig/userextension.php

namespace Acme\BaseBundle\Twig;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Security\Core\SecurityContext;
use Acme\UserBundle\Entity\User;

class UserExtension extends \Twig_Extension
{
    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    protected $container;

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

    public function getFunctions()
    {
        return array(
            'getAbcData' => new \Twig_SimpleFunction('getAbcData', $this->getAbcData()),
        );
    }

    public function getAbcData()
    {
        if ( !is_object($user = $this->container->get('security.context')->getToken()->getUser()) || !$user instanceof User){ return null; }
        return array(
            'data_array'   => $user->getData(),
        );
    }

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


来源:https://stackoverflow.com/questions/24916638/symfony-dependency-injection-in-twig-extension

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!