Cannot autowire service: Argument references class but no such service exists
Solution 1
Starting from the 1.8 version of DoctrineBundle, you can extend your class using Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository
instead of Doctrine\ORM\EntityRepository
. The result will be the same, but this does support the autowire.
Example:
use App\Entity\Activation;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;
class ActivationRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Activation::class);
}
// ...
}
Solution 2
Do you really need to add service definitions to services.yaml for third party vendor classes?
No, don't do that. My personal suggestion is: don't extend EntityRepository
. Ever. You don't want your repository's interface to have method like createQuery
or flush
. At least, you don't want that if you consider a repository just like a collection of objects. If you extend EntityRepository
you will have a leaky abstraction.
Instead you can inject the EntityManager
inside your repository, and that's it:
use App\Entity\Activation;
use App\Repository\ActivationRepository;
use Doctrine\ORM\EntityManagerInterface;
final class DoctrineActivationRepository implements ActivationRepository
{
private $entityManager;
private $repository;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
$this->repository = $this->entityManager->getRepository(Activation::class);
}
public function store(Activation $activation): void
{
$this->entityManager->persist($activation);
$this->entityManager->flush();
}
public function get($id): ?Activation
{
return $this->repository->find($id);
}
// other methods, that you defined in your repository's interface.
}
No other steps are required.
Solution 3
My issue was a wrong namespace.
File real position was App\Infrastructure\MySQL\Rubric\Specification
But namespace was set to App\Infrastructure\Rubric\Specification
Result "[blah blah] but no such service exists".
NiqT
Hi! Donal is my name and I've been a Web Developer since 2009. My passion in life is making webpages for millions of people to enjoy and playing with the latest technologies is the best bit! Feel free to get in touch with me, but please, no spam..
Updated on April 15, 2021Comments
-
NiqT about 3 years
I'm upgrading a project from Symfony 3 to Symfony 4 (https://github.com/symfony/symfony/blob/master/UPGRADE-4.0.md) and I have many repository/services like this:
namespace App\Entity; use App\Entity\Activation; use Doctrine\ORM\EntityRepository; use Predis\Client; class ActivationRepository extends EntityRepository { // ... }
And when I try to run the project in the browser like this:
http://localhost:8000/login
I get this error:
(1/1) RuntimeException Cannot autowire service "App\Entity\ActivationRepository": argument "$class" of method "Doctrine\ORM\EntityRepository::__construct()" references class "Doctrine\ORM\Mapping\ClassMetadata" but no such service exists.
Does this mean you have to create a service for "Doctrine\ORM\Mapping\ClassMetadata" in your services.yaml file?
Thanks to autowiring my new services.yaml file is fairly small compared to the old one, which had 2000+ lines. The new services.yaml just has several of these (so far):
App\: resource: '../src/*' # Controllers App\Controller\: resource: '../src/Controller' autowire: true public: true tags: ['controller.service_arguments'] # Models App\Model\: resource: '../src/Model/' autowire: true public: true // etc
Question: Do you really need to add service definitions to services.yaml for third party vendor classes? And if so, can I get an example of how to do that please? Any advice from anyone who has already upgraded from Symfony 3 to Symfony 4 would be great.
PHP 7.2.0-2+ubuntu16.04.1+deb.sury.org+2 (cli) (built: Dec 7 2017 20:14:31) ( NTS ) Linux Mint 18, Apache2 Ubuntu.
EDIT / FYI:
This is the "Doctrine\ORM\EntityRepository::__construct()" which the ActivationRepository extends:
/** * Initializes a new <tt>EntityRepository</tt>. * * @param EntityManager $em The EntityManager to use. * @param Mapping\ClassMetadata $class The class descriptor. */ public function __construct(EntityManagerInterface $em, Mapping\ClassMetadata $class) { $this->_entityName = $class->name; $this->_em = $em; $this->_class = $class; }
which is located here:
/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php
-
Cerad over 6 yearsDoctrine's repositories are more than a collection of objects. Nor is it clear how have a store method fit's in with a collection of objects. I understand what you are saying but your solution is overkill.
-
Federkun over 6 yearsYeah, I know, I'm talking about
collections
and use an example with astore
method, that's more persistence-oriented instead of collection-oriented. But if I replace that with anadd
method the next question iswhere I commit my changes?
and we make the example too complex. Still, I don't think that this is overkill. But I guess it's just my personal opinion. Like everything, there's pro and cons. Using the EntityManager service locator has pro and cons as well. -
Vadim Ashikhman over 6 yearsInjecting EntityManager for getting repository objects is like injecting Symfony DI container. If there is no way to autowire repository classes the only way is to define them in the services.yml. The subject is not about where to put persistent logic, it's about autowiring Doctrine repository classes.
-
Federkun over 6 years@VadimAshikhman, I don't mind provide the answer to that specific question: stackoverflow.com/a/48026278/711206 But you will notice that that solution is even worst than this one.
-
Vadim Ashikhman over 6 years@Federkun, wow, nice solution! In my personal opinion i think it is better than injecting the manager and calling it's
getRepository()
method, so you can only instantiate repository object that corresponds to only 1 entity. -
Federkun over 6 yearsYou will need to overwrite
ServiceEntityRepository#__construct
for each repository, and under the hoodServiceEntityRepository
will do the same thing as what I described here. I guess that, in the end, it's more of a "choose your poison"-kinda of answer. Personally, I'll stick with what I suggested here. But, of course, everybody should choose what works better for them. Cheers! -
Vadim Ashikhman over 6 years@Federkun, I agree with you, when you know much about a library you are using you can make many things which developers didn't think of. Hell, you can always use reflection to make something bad. In case of new developers that are joining a project, they will just use single entity class in the constructor, instead of getting any repository from the manager/registry.
-
WalterEgo almost 6 yearsThank you Federkun and Massimiliano Arione. Not sure what bits you did between you, but you just helped me get one more step towards the end of my Symfony 3.4 to 4 journey.
-
Cristiano Casciotti about 4 yearsJust a note for who are using
doctrine/persistence >= 1.3
used bydoctrine-bundle 2.x
, useDoctrine\Persistence\ManagerRegistry
instead ofDoctrine\Common\Persistence\ManagerRegistry
-
Zoltán Süle over 3 yearsI would mention that because it is also important that they have to create a constructor and define the
entityClass
as you already did in your example. -
barell over 3 yearsBeware that presented "store()" method seems convenient it kills the concept of having Doctrine to manage all writes done in a single transaction where possible. Use it only if you know what are you doing. Not sure why people are so hesitant to use entity manager directly in controllers/services and delegate things to repository/model managers etc.