Reputation: 173
Well, I'm going crazy, there's something I don't get with the Symfony (3.3) autowiring stuff. I've read those resources : http://symfony.com/doc/current/service_container.html http://symfony.com/doc/current/service_container/3.3-di-changes.html and others that I can't post because I need 10 reputation. I've also read many articles/stackoverflow posts, but with no luck.
I've tried to set up my services, and it almost works, it's just that the EntityManager is null, so I can't call ->getRepository()
on it. The error happens on the line like this in my factory:
$databaseTournament = $this->em->getRepository('AppBundle:Tournament')
->find($tournament);
"Call to a member function getRepository() on null"
It seems to find the services correctly but never injects the EntityManager in the factory. I've tried to configure things explicitely in the services.yml, but I never managed to make it work.
I'm trying to figure it ou since yesterday, but I'm getting really confused. Could you help me ? Thank you in advance ! :)
Here are my files :
parameters:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
AppBundle\:
resource: '../../src/AppBundle/*'
exclude: '../../src/AppBundle/{Entity,Repository,Tests}'
AppBundle\Controller\:
resource: '../../src/AppBundle/Controller'
public: true
tags: ['controller.service_arguments']
<?php
namespace AppBundle\Factory;
use AppBundle\Entity\Entry;
use AppBundle\Entity\Team;
use AppBundle\Entity\Tournament;
use AppBundle\Exception\InvalidEntryArgumentException;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityNotFoundException;
class EntryFactory
{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function createEntry($tournament, $team, $eliminated = false)
{
$entry = new Entry();
if ($tournament instanceof Tournament) {
$entry->setTournament($tournament);
}
elseif (is_int($tournament) && $tournament >= 0) {
$databaseTournament = $this->em->getRepository('AppBundle:Tournament')->find($tournament);
if (is_null($databaseTournament)) {
throw new EntityNotFoundException('Tournament (id:'.$tournament.') not found.');
}
else {
$entry->setTournament($databaseTournament);
}
}
else {
throw new InvalidEntryArgumentException('Could not determine the Tournament argument.');
}
if ($team instanceof Team) {
$entry->setTeam($team);
}
elseif (is_int($team) && $team >= 0) {
$databaseTeam = $this->em->getRepository('AppBundle:Team')->find($team);
if (is_null($databaseTeam)) {
throw new EntityNotFoundException('Team (id:'.$team.') not found.');
}
else {
$entry->setTeam($databaseTeam);
}
}
else {
throw new InvalidEntryArgumentException('Could not determine the Team argument.');
}
$entry->setEliminated($eliminated);
return $entry;
}
}
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Entry;
use Doctrine\ORM\EntityNotFoundException;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\View\View;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\ConstraintViolationList;
use AppBundle\Factory;
class EntryController extends FOSRestController
{
/**
* @ApiDoc(
* resource=true,
* section="Entries",
* description="Creates a new entry.",
* statusCodes={
* 201="Returned when created.",
* 400="Returned when a violation is raised by validation.",
* 404="Returned when a team or a tournament is not found."
* }
* )
*
* @Rest\Post(
* path="/entries",
* name="app_entry_create"
* )
* @Rest\View(statusCode=201)
* @Rest\RequestParam(
* name="tournamentId",
* requirements="\d+",
* nullable=false,
* description="The id of the tournament in which the team enters."
* )
* @Rest\RequestParam(
* name="teamId",
* requirements="\d+",
* nullable=false,
* description="The id of the team entering the tournament."
* )
*
* @param $tournamentId
* @param $teamId
* @param ConstraintViolationList $violationList
* @param Factory\EntryFactory $entryFactory
* @return Entry|View
* @throws EntityNotFoundException
* @internal param $id
* @internal param Entry $entry
*/
public function createEntryAction($tournamentId, $teamId, ConstraintViolationList $violationList,
Factory\EntryFactory $entryFactory)
{
if (count($violationList)) {
return $this->view($violationList, Response::HTTP_BAD_REQUEST);
}
$entry = $entryFactory->createEntry($tournamentId,$teamId);
$em->persist($entry);
$em->flush();
return $entry;
}
}
edit:
I must add that I've tried this and it doesn't work either:
in the services.yml:
AppBundle\Factory\EntryFactory:
public: true
arguments: ['@doctrine.orm.entity_manager']
in the EntryFactory:
public function __construct(EntityManager $em)
{
$this->em = $em;
}
edit 2:
I've also tried to disable everything new : still the same error
AppBundle\Factory\EntryFactory:
autowire: false
autoconfigure: false
public: true
arguments:
$em: '@doctrine.orm.entity_manager'
Same with disabling the folder in the default config :
AppBundle\:
resource: '../../src/AppBundle/*'
exclude: '../../src/AppBundle/{Entity,Repository,Tests,Factory}'
Upvotes: 3
Views: 6930
Reputation: 18416
An alternative to force autowiring Dependency Injection in Symfony 3.3 or later, without having to explicitly define the entity manager for each service. You can add an alias of the desired entity manager service.
#app/config/services.yml
services:
_defaults:
autowire: true
autoconfigure: true
public: false
AppBundle\:
resource: '../../src/AppBundle/*'
exclude: '../../src/AppBundle/{Entity,Repository,Tests}'
AppBundle\Controller\:
resource: '../../src/AppBundle/Controller/*'
public: true
tags: ['controller.service_arguments']
Doctrine\ORM\EntityManagerInterface: '@doctrine.orm.entity_manager'
#custom services below here
#...
This will then allow Symfony to determine Doctrine\ORM\EntityManagerInterface
as the service you want to inject.
use Doctrine\ORM\EntityManagerInterface;
class EntryFactory
{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
//...
}
End result will be in your services configuration as:
return $this->services['AppBundle\Factory\EntryFactory'] = new \AppBundle\Factory\EntryFactory(${($_ = isset($this->services['doctrine.orm.default_entity_manager']) ? $this->services['doctrine.orm.default_entity_manager'] : $this->load('getDoctrine_Orm_DefaultEntityManagerService.php')) && false ?: '_'});
Note: Be sure to warmup your Symfony cache to ensure new service declarations are created.
php composer.phar install
or
php composer.phar install --no-scripts php bin/console --env=dev cache:clear --no-warmup php bin/console --env=dev cache:warmup
Upvotes: 1