问题
I have a simple, working SecurityController that I would like to turn into a bundle so that I can share basic authentication functionality across a few basic websites I create. Everything is working as desired until I try to turn my code into a bundle.
I have created my bundle class, a Resources/config/routing.xml file to declare my login and logout routes, have a template in Resources/views/Security/login.html.twig but the following class is throwing an error.
<!-- Controller/SecurityController.php -->
<?php
namespace JustinVoelker\EssentialSecurityBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends AbstractController
{
private $authenticationUtils;
public function __construct(AuthenticationUtils $authenticationUtils)
{
$this->authenticationUtils = $authenticationUtils;
}
public function loginAction()
{
$error = $this->authenticationUtils->getLastAuthenticationError();
return $this->render('@EssentialSecurity/Security/login.html.twig', [
'error' => $error,
]);
}
... Comments and additional functions removed for simplicity
}
The error I am getting when I go to the login page is Controller "JustinVoelker\EssentialSecurityBundle\Controller\SecurityController" has required constructor arguments and does not exist in the container. Did you forget to define such a service?
Following a few different examples/tutorials, I tried creating a services.xml file and loading it via DependencyInjection/EssentialSecurityExtension.php in an attempt to make AuthenticationUtils available to my constructor but that does not appear to change anything.
<!-- DependencyInjection/EssentialSecurityExtension.php -->
<?php
namespace JustinVoelker\EssentialSecurityBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
class EssentialSecurityExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$loader = new XmlFileLoader(
$container,
new FileLocator(__DIR__.'/../Resources/config')
);
$loader->load('services.xml');
}
}
<!-- Resources/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="essential_security.controller"
class="JustinVoelker\EssentialSecurityBundle\Controller\SecurityController">
<argument type="service" id="security.authentication_utils"/>
</service>
</services>
</container>
What am I missing that allows me to use dependency injection inside a bundle as I was able to before moving this code into a bundle?
If I simply remove any reference to AuthenticationUtils (the private property, the entire constructor, and its usage inside loginAction) the page renders, though it will not function as desired without that last authentication error that I am using AuthenticationUtils for in the first place.
Side note, if I manually add JustinVoelker\EssentialSecurityBundle\Controller\SecurityController: ~
to my applications main config/services.xml file, The controller error disappears so clearly I'm missing something inside my bundle to make this work.
Perhaps there is another way to achieve my ultimate end goal of returning the last authentication error message to the login page, but my question is what am I missing that is preventing this dependency injection from working as it did before I bundled my controller and as it appears to work in so many examples I've seen.
EDIT 2019-05-30 Including a portion of my original routing.xml
<route id="essential_security_login" path="/login">
<default key="_controller">EssentialSecurityBundle:Security:login</default>
</route>
回答1:
Looks like in your routing you use JustinVoelker\EssentialSecurityBundle\Controller\SecurityController
but your service name is essential_security.controller
You should either change your routing or service definition
You can add an alias
<!-- Resources/config/services.xml -->
<service id="JustinVoelker\EssentialSecurityBundle\Controller\SecurityController" alias="essential_security.controller"/>
<service id="essential_security.controller" class="JustinVoelker\EssentialSecurityBundle\Controller\SecurityController">
<argument type="service" id="security.authentication_utils"/>
<tag name="controller.service_arguments"/>
</service>
or just rename it (note you can omit class
parameter)
<!-- Resources/config/services.xml -->
<service id="JustinVoelker\EssentialSecurityBundle\Controller\SecurityController">
<argument type="service" id="security.authentication_utils"/>
<tag name="controller.service_arguments"/>
</service>
or in your routing:
route_name:
path: /path
controller: JustinVoelker\EssentialSecurityBundle\Controller\SecurityController::loginAction
route_name:
path: /path
controller: essential_security.controller::loginAction
depends on your service name
来源:https://stackoverflow.com/questions/56370800/dependency-injection-for-a-bundle-controller