'Cannot autowire service in symfony

I'm trying to split one big service.yaml to few smaller files. In origin service.yaml I had

services:

_defaults:
    autowire: true
    autoconfigure: true
    public: false

App\Domain\Country\Infrastructure\Repository\CountryRepository:
    public: true
    class: App\Domain\Country\Infrastructure\Repository\CountryRepository
    factory: ["@doctrine.orm.default_entity_manager", getRepository]
    arguments: [App\Domain\Country\Entity\Country]

Then I added import at the begining service.yam

imports:
  - {resource: services/repositories.yaml}

repositories.yaml

services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: true

     App\Domain\Country\Infrastructure\Repository\CountryRepository:
        factory: ["@doctrine.orm.default_entity_manager", getRepository]
        arguments: [App\Domain\Country\Entity\Country]

After that I started to get error

  Cannot autowire service "App\Domain\Country\Infrastructure\Repository\Count  
  ryRepository": argument "$class" of method "Doctrine\ORM\EntityRepository::  
  __construct()" references class "Doctrine\ORM\Mapping\ClassMetadata" but no  
   such service exists.  

What's wrong there?



Solution 1:[1]

You should not need to define the repository for the purposes of autowiring.

services.yaml:

services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: false

    App\:
        resource: '../src/*'
        exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'

    App\Controller\:
        resource: '../src/Controller'
        tags: ['controller.service_arguments']

Entity\Country:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\CountryRepository")
 */
class Country
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $name;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }
}

Repository\CountryRepository:

<?php

namespace App\Repository;

use App\Entity\Country;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;

/**
 * @method Country|null find($id, $lockMode = null, $lockVersion = null)
 * @method Country|null findOneBy(array $criteria, array $orderBy = null)
 * @method Country[]    findAll()
 * @method Country[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 */
class CountryRepository extends ServiceEntityRepository
{
    public function __construct(RegistryInterface $registry)
    {
        parent::__construct($registry, Country::class);
    }
}

And finally, your service:

<?php

namespace App\Service;

use App\Repository\CountryRepository;

class ExampleService
{
    /**
     * @var CountryRepository
     */
    private $repository;

    /**
     * @param CountryRepository $repository
     */
    public function __construct(CountryRepository $repository)
    {
        $this->repository = $repository;
    }
}

The autowiring will see that you've injected that CountryRepository into the ExampleService constructor and handle the rest.

Solution 2:[2]

Use named arguments instead :

repositories.yaml

services:

     App\Domain\Country\Infrastructure\Repository\CountryRepository:
        factory: ["@doctrine.orm.default_entity_manager", getRepository]
        arguments:
            $class: '@App\Domain\Country\Entity\Country'

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 OK sure
Solution 2 Pmpr.ir