Symfony 3.4 自动装配服务

Posted

技术标签:

【中文标题】Symfony 3.4 自动装配服务【英文标题】:Symfony 3.4 autowire service 【发布时间】:2018-08-05 07:48:18 【问题描述】:

我正在用 Symfony 3.4 开发一个迷你应用程序。我正在使用 Guard 组合一个身份验证过程。我创建了一个名为 LoginFormAuthenticator 的类,它扩展了 AbstractFormLoginAuthenticator。

接收错误:

无法自动装配服务“app.security.login_form_authenticator”:方法的参数“$em” “AppBundle\Security\LoginFormAuthenticator::__construct()”引用 类“Doctrine\ORM\EntityManager”,但不存在这样的服务。尝试 将类型提示更改为其父项之一:接口 “Doctrine\ORM\EntityManagerInterface”,或接口 "Doctrine\Common\Persistence\ObjectManager"。

我的表单验证类中的代码:

    <?php

namespace AppBundle\Security;


use AppBundle\Form\LoginForm;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;

class LoginFormAuthenticator extends AbstractFormLoginAuthenticator

    private $formFactory;
    private $em;
    private $router;

    public function __construct(FormFactoryInterface $formFactory, EntityManager $em, RouterInterface $router)
    

        $this->formFactory = $formFactory;
        $this->em = $em;
        $this->router = $router;
    

    public function getCredentials(Request $request)
    
        $isLoginSubmit = $request->getPathInfo() == '/login' && $request->isMethod('POST');

        if(!$isLoginSubmit)
            return false;
        

        $form = $this->formFactory->create(LoginForm::class);
        $form->handleRequest($request);

        $data = $form->getData();
        return $data;
    

    public function getUser($credentials, UserProviderInterface $userProvider)
    
        $username = $credentials['_username'];

        return $this->em->getRepository('AppBundle:User')
            ->findOneBy(['email' => $username]);
    

    public function checkCredentials($credentials, UserInterface $user)
    
        $password = $credentials['_password'];
        if($password == 'iliketurtles')
            return true;
        
        return false;
    

    protected function getLoginUrl()
    
        return $this->router->generate('security_login');
    

我的 services.yml:

services:
# default configuration for services in *this* file
_defaults:
    # automatically injects dependencies in your services
    autowire: true
    # automatically registers your services as commands, event subscribers, etc.
    autoconfigure: true
    # this means you cannot fetch services directly from the container via $container->get()
    # if you need to do this, you can override this setting on individual services
    public: false

# makes classes in src/AppBundle available to be used as services
# this creates a service per class whose id is the fully-qualified class name
AppBundle\:
    resource: '../../src/AppBundle/*'
    # you can exclude directories or files
    # but if a service is unused, it's removed anyway
    exclude: '../../src/AppBundle/Entity,Repository,Tests'

# controllers are imported separately to make sure they're public
# and have a tag that allows actions to type-hint services
AppBundle\Controller\:
    resource: '../../src/AppBundle/Controller'
    public: true
    tags: ['controller.service_arguments']

# add more services, or override services that need manual wiring
# AppBundle\Service\ExampleService:
#     arguments:
#         $someArgument: 'some_value'

app.security.login_form_authenticator:
    class: AppBundle\Security\LoginFormAuthenticator
    autowire: true 

我是 Symfony 的完全新手,如果我遗漏了一些明显的东西,敬请见谅。

【问题讨论】:

在构造函数中将 EntityManager 更改为 EntityManagerInterface。 完美!成功了,谢谢! 很高兴能提供帮助。现在,虽然它还很新鲜,但请花点时间了解它的工作原理:symfony.com/doc/current/service_container/autowiring.html 如果至少对 autowire 和服务容器有基本的了解,您将不会对 S4 走得太远。并且“bin/console debug:container --show-private”应该成为你最好的朋友之一。 我不明白为什么这个问题被赞成。错误消息中提到了答案:“尝试将类型提示更改为其父项之一:接口“Doctrine\ORM\EntityManagerInterface” 因为人们不只是相信错误消息 - 有解释的社区,为了胜利! 【参考方案1】:

正如 @Cerad 在 cmets 中所指出的,您应该在构造函数中将 EntityManager 更改为 EntityManagerInterface。

换行

use Doctrine\ORM\EntityManager;

use Doctrine\ORM\EntityManagerInterface;

还有换行

public function __construct(FormFactoryInterface $formFactory, EntityManager $em, RouterInterface $router)

public function __construct(FormFactoryInterface $formFactory, EntityManagerInterface $em, RouterInterface $router)

【讨论】:

伙计们,这个问题已经在 cmets 中得到了回答,但我决定“真实”回答它,所以它不再出现在“未回答的问题”搜索中。【参考方案2】:

Doctrine\Common\Persistence\ObjectManager 接口不再别名为doctrine.orm.entity_manager 服务,改为使用Doctrine\ORM\EntityManagerInterface

【讨论】:

以上是关于Symfony 3.4 自动装配服务的主要内容,如果未能解决你的问题,请参考以下文章

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

Symfony 自动装配独白通道

Symfony 4 不自动装配动态路由控制器

无法自动装配服务:参数引用类但不存在此类服务

使用 Symfony 自动装配时是不是可以排除多个目录?

如何自动装配服务,进而在 Junit 中自动装配另一个服务