Symfony 3 - 无法将 token_storage 传递给订阅者

Posted

技术标签:

【中文标题】Symfony 3 - 无法将 token_storage 传递给订阅者【英文标题】:Symfony 3 - Can't pass token_storage to from subscriber 【发布时间】:2017-10-25 16:21:07 【问题描述】:

我想在表单事件中获取当前登录的用户,但由于某种原因我无法让它工作。

我使用服务注入 token_storage 并创建构造函数方法来获取令牌存储实例,但我在构造函数处遇到错误:

Type error: Argument 1 passed to AdminBundle\Form\EventListener\CompanyFieldSubscriber::__construct() must implement interface Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface, none given

我不确定是什么问题以及如何解决它。有人知道问题出在哪里吗?

编辑 1:

我想我发现问题出在哪里,但我找不到“好的”解决方案。我以这种方式在表单类型中调用此事件:

->addEventSubscriber(new CompanyFieldSubscriber());

问题是我没有使用“服务/依赖注入”来创建事件,并且我没有向构造函数发送任何内容。这就是我有这个错误的原因(不是 100% 肯定是诚实的)。

由于我有大约 20-30 个表单并且新表单会及时出现,我需要为每个需要用户(或 token_storage)实例的表单创建服务,并作为参数调用 token_storage 或此事件订阅者作为服务参数。

我知道,如果我将每个表单创建为服务并将所需数据作为参数传递,它会起作用,但是有没有办法“自动”处理这个,而不需要为需要在表单中进行一些用户数据交互的每个表单创建新服务活动?

编辑 2:

按照建议,我尝试更改事件订阅者构造函数,但使用不同的类名时出现相同的错误。

新代码:

use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;

public function __construct(TokenStorage $tokenStorage)
    
        $this->tokenStorage = $tokenStorage;
    

新错误:

Type error: Argument 1 passed to AdminBundle\Form\EventListener\CompanyFieldSubscriber::__construct() must be an instance of Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage, none given

这是我正在使用的代码:

服务:

admin.form.event_listener.company:
    class:  AdminBundle\Form\EventListener\CompanyFieldSubscriber
    arguments: ['@security.token_storage']
    tags:
        -  name: form.event_listener 

事件监听器:

namespace AdminBundle\Form\EventListener;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class CompanyFieldSubscriber implements EventSubscriberInterface

    private $tokenStorage;

    private $user;

    public function __construct(TokenStorageInterface $tokenStorage)
    
        $this->tokenStorage = $tokenStorage;
        $this->user = $this->tokenStorage->getToken()->getUser();
    

    public static function getSubscribedEvents()
    
        return [
            FormEvents::PRE_SET_DATA => 'preSetData',
            FormEvents::PRE_SUBMIT => 'preSubmitData',

        ];
    

    public function preSetData(FormEvent $event)
    

        $form = $event->getForm();

        if (in_array("ROLE_SUPER_ADMIN", $this->user->getRoles())) 
            $form->add('company', EntityType::class, [
                'class' => 'AppBundle:Company',
                'choice_label' => 'name'
            ]);
        
    

    public function preSubmitData(FormEvent $event)
    

        $form = $event->getForm();
        $bus = $form->getData();


        if (!in_array("ROLE_SUPER_ADMIN", $this->user->getRoles())) 
            $bus->setCompany($this->user->getCompany());

        
    

【问题讨论】:

【参考方案1】:

您在使用时以错误的方式呼叫订阅者:

new CompanyFieldSubscriber()

您没有将 TokenStorageInterface 传递给订阅者构造函数。将其作为服务调用,如果它在控制器中,则:

->addEventSubscriber($this->get('admin.form.event_listener.company'));

如果它在表单中,则从控制器传递到表单

$this->get('admin.form.event_listener.company') 

作为选项,然后在表单中使用它

【讨论】:

感谢您的评论@Eimsas。我会尝试您的代码,但我不确定是否存在问题。我遵循了 symfony 网站上的教程,他们以与我注入相同的方式注入当前登录的用户,但他们以表单类型进行。 注入一切正常,你只是使用了错误的对象,你使用接口而不是令牌存储本身 我试过你的代码,同样的错误出现了不同的类名错误。我认为问题在于调用事件订阅者。将更新我的原始问题以提供更多信息 没有问题是令牌存储读取错误:“必须实现接口 Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface, none given” in the services.yml 你注入 Symfony\ Component\Security\Core\Authentication\Token\Storage\TokenStorage 并在您使用的订阅者中使用 Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;也许您忘记将构造函数从 TokenStorageInterface 更改为 TokenStorage 我使用了您提供的新代码,但弹出相同的错误并使用不同的类名。检查我更新的帖子。我认为现在会更清楚。另外,感谢您的宝贵时间。【参考方案2】:

对于 Symfony >= 4

use Symfony\Component\Security\Core\Security;

class ExampleService

    private $security;

    public function __construct(Security $security)
    
        $this->security = $security;
    

    public function someMethod()
    
        $user = $this->security->getUser();
    

见文档:https://symfony.com/doc/current/security.html#fetching-the-user-from-a-service

【讨论】:

以上是关于Symfony 3 - 无法将 token_storage 传递给订阅者的主要内容,如果未能解决你的问题,请参考以下文章

从 Symfony 3.4 迁移到 Symfony 4.4 后,自定义投票器无法按预期工作

Hwi oauth bundle 和 Symfony 3.4 无法自动装配服务:如何在 symfony 3.4 + FOSUserBundle 中使用 hwi/oauth-bundle

无法自动装配服务 FOSUserBundle,Symfony 3.4

Symfony 3 无法使用 ajax 登录

Symfony 5 无法将 EntityManagerInterface 注入验证器

无法使用 symfony 5 安装奏鸣曲管理员