树枝延伸中的Symfony依赖注入

时间:2014-07-23 17:03:04

标签: symfony service dependency-injection twig

好的,我正在尝试创建具有依赖于其他服务(security.context)的twig扩展,并遇到了一些麻烦。所以,这是我的服务声明:

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

这是我的班级

// 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';
    }
}

最后,我有一个错误:

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

我想 security.context 服务尚未初始化,然后我收到错误。 任何人都可以告诉,是否有手动加载服务的方法,或任何更好的问题解决方案? 非常感谢。


我使用Symfony 2.5。*

UPD:

我也在symfony docs

中找到了这个通知
  

请注意,Twig Extensions不会延迟加载。这意味着,如果任何服务(或本例中的Twig扩展)依赖于请求服务,您将获得CircularReferenceException或ScopeWideningInjectionException的可能性更高。有关更多信息,请参阅如何使用范围。   实际上,我不知道如何纠正它。

3 个答案:

答案 0 :(得分:2)

在构建Twig_SimpleFilter时,您调用 $this->getAbcData()。但你必须传递一个callable作为参数。

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

狮子座也是对的。在尝试getToken()之前,您应首先检查getToken()->getUser()是否正在返回对象。

您还可以将用户作为参数传递给该函数:{{ getAbcData(app.user) }}。这样,该函数更通用,可以用于任何用户,而不仅仅是当前登录的用户。

答案 1 :(得分:1)

这应该可行。错误消息表示getToken()不是对象,因此如果getUser()也是对象,则必须在测试之前测试getToken()是否为对象。

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

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

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

答案 2 :(得分:1)

您需要更改twig扩展名,以使容器不是安全上下文传递给构造函数。

Twig_Extensions的特殊之处在于,普通的规则不会传递到容器中,而是仅传递您经常不应用的内容,因为它会因范围问题而导致问题。

因此请将您的扩展程序更改为此类。

// 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';
    }
}