Am developing a mini app in Symfony 3.4. Am putting together an authentication process using Guard. I have created a class called LoginFormAuthenticator which extends AbstractFormLoginAuthenticator.
Receiving error:
Cannot autowire service "app.security.login_form_authenticator": argument "$em" of method "AppBundle\Security\LoginFormAuthenticator::__construct()" references class "Doctrine\ORM\EntityManager" but no such service exists. Try changing the type-hint to one of its parents: interface "Doctrine\ORM\EntityManagerInterface", or interface "Doctrine\Common\Persistence\ObjectManager".
My code in my form authenticating class:
<?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');
}
}
My 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
Am a complete novice in Symfony so apologies if I'm missing something obvious.
Autowiring Logic Explained Autowiring isn't magic: it looks for a service whose id matches the type-hint. If you load services automatically, each service's id is its class name. If there is not a service whose id exactly matches the type, a clear exception will be thrown.
In Symfony, these useful objects are called services and each service lives inside a very special object called the service container. The container allows you to centralize the way objects are constructed. It makes your life easier, promotes a strong architecture and is super fast!
A Service Container (or dependency injection container) is simply a PHP object that manages the instantiation of services (i.e. objects). For example, suppose you have a simple PHP class that delivers email messages. Without a service container, you must manually create the object whenever you need it: Copy.
Autowiring is an exotic word that represents something very simple: the ability of the container to automatically create and inject dependencies. In order to achieve that, PHP-DI uses PHP's reflection to detect what parameters a constructor needs. Autowiring does not affect performances when compiling the container.
As noted by @Cerad in the comments, you should change EntityManager to EntityManagerInterface in your constructor.
use Doctrine\ORM\EntityManager;
to
use Doctrine\ORM\EntityManagerInterface;
public function __construct(FormFactoryInterface $formFactory, EntityManager $em, RouterInterface $router)
to
public function __construct(FormFactoryInterface $formFactory, EntityManagerInterface $em, RouterInterface $router)
The Doctrine\Common\Persistence\ObjectManager interface is no longer aliased to the doctrine.orm.entity_manager service, use Doctrine\ORM\EntityManagerInterface instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With