I want to refactoring my code, but now i have error and don't understand what. Objectif : Don't need to pass parameters when call TokenService, and use autowiring to autowiring EntityManager & Request, and don't set it when controller call service.
Cannot resolve argument $tokenService of App\Controller\TokenController::showTokens() Cannot autowire service App\Service\TokenService argument $request of method __construct() references class Symfony\Component\HttpFoundation\Request but no such service exists.
Before :
/src/Controller/TokenController.php
<?php
namespace App\Controller;
use App\Service\TokenService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* @Route("/v1")
*/
class TokenController
{
/** @var EntityManagerInterface $em */
private $em;
/** @var Request $request */
private $request;
/**
* TokenService constructor.
*
* @param Request $request
* @param EntityManagerInterface $em
*/
public function __construct(Request $request, EntityManagerInterface $em)
{
$this->request = $request;
$this->em = $em;
}
public function showTokens(Request $request, EntityManagerInterface $em): JsonResponse
{
$tokenService = new TokenService($request, $em);
return $tokenService->getTokens();
}
}
/src/Service/TokenService.php
<?php
namespace App\Service;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Class TokenService
* @package App\Service
*/
class TokenService
{
/** @var EntityManagerInterface $em */
private $em;
/** @var Request $request */
private $request;
/**
* TokenService constructor.
*
* @param Request $request
* @param EntityManagerInterface $em
*/
public function __construct(Request $request, EntityManagerInterface $em)
{
$this->request = $request;
$this->em = $em;
}
public function getTokens()
{
return true;
}
}
After :
/config/services.yaml
parameters:
services:
_defaults:
autowire: true
autoconfigure: true
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
- '../src/Tests/'
App\Controller\:
resource: '../src/Controller/'
tags: ['controller.service_arguments']
App\Service\TokenService: ~
/src/Controller/TokenController.php
<?php
namespace App\Controller;
use App\Service\TokenService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* @Route("/v1")
*/
class TokenController
{
public function showTokens(Request $request, EntityManagerInterface $em, TokenService $tokenService): JsonResponse
{
return $tokenService->getTokens();
}
/src/Service/TokenService.php
<?php
namespace App\Service;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Class TokenService
* @package App\Service
*/
class TokenService
{
/** @var EntityManagerInterface $em */
private $em;
/** @var Request $request */
private $request;
/**
* TokenService constructor.
*
* @param Request $request
* @param EntityManagerInterface $em
*/
public function __construct(Request $request, EntityManagerInterface $em)
{
$this->request = $request;
$this->em = $em;
}
public function getTokens()
{
return true;
}
}
Thanks !
I guess it's been awhile since we had a good request stack question. I did a bit of a search and did not find any answer that was directly applicable and provided a decent explanation.
The basic issue is that the Symfony framework supports nested requests. You get these, for example, when using embedded controllers. So there is no actual request service. There actually used to be when Symfony 2.0 was first released but it was a real mess. Supporting nested request services was done at the container level and it was not fun.
So a big hammer known as the request stack was introduced to solve the problem once and for all. You inject the request stack instead of the request and then access the request when you actually need it.
class TokenService
{
private $em;
private $requestStack;
public function __construct(RequestStack $requestStack, EntityManagerInterface $em)
{
$this->requestStack = $requestStack;
$this->em = $em;
}
public function getTokens()
{
$request = $this->requestStack->getMainRequest(); // or possibly getCurrentRequest depending on where the tokens are
return true;
}
Having said that, I would personally just pass the request from the controller. Doing so gets rid of that 'it depends' comment of mine. I also thinks it reduces the 'magic' involved just a bit. Both approaches will work.
class TokenService
{
public function getTokens(Request $request)
{
return true;
}
...
class TokenController
{
public function showTokens(Request $request, TokenService $tokenService): JsonResponse
{
return $tokenService->getTokens($request);
}