Je suis en train de mettre à niveau un projet de Symfony 3 à Symfony 4 (- https://github.com/symfony/symfony/blob/master/UPGRADE-4.0.md ) et j'ai de nombreux référentiels/services comme celui-ci:
namespace App\Entity;
use App\Entity\Activation;
use Doctrine\ORM\EntityRepository;
use Predis\Client;
class ActivationRepository extends EntityRepository
{
// ...
}
Et quand j'essaye de lancer le projet dans le navigateur comme ceci:
http://localhost:8000/login
Je reçois cette erreur:
(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.
Cela signifie-t-il que vous devez créer un service pour "Doctrine\ORM\Mapping\ClassMetadata" dans votre fichier services.yaml?
Merci à autowiring mon nouveau fichier services.yaml est assez petit comparé à l'ancien, qui avait plus de 2000 lignes. Le nouveau services.yaml en a plusieurs (jusqu'à présent):
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: Avez-vous vraiment besoin d’ajouter des définitions de service à services.yaml pour les classes de fournisseurs tiers? Et si oui, puis-je avoir un exemple de la façon de le faire s'il vous plaît? Tout conseil de toute personne ayant déjà mis à niveau de Symfony 3 à Symfony 4 serait génial.
PHP 7.2.0-2 + ubuntu16.04.1 + deb.sury.org + 2 (cli) (build: 7 déc. 2017 20:14:31) (NTS) Linux Mint 18, Apache2 Ubuntu.
EDIT/FYI:
Ceci est le "Doctrine\ORM\EntityRepository :: __ construct ()" que ActivationRepository étend:
/**
* 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;
}
qui se trouve ici:
/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php
À partir de la version 1.8 de DoctrineBundle, vous pouvez étendre votre classe en utilisant Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository
au lieu de Doctrine\ORM\EntityRepository
. Le résultat sera le même, mais cela prend en charge le fil automatique.
Exemple:
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);
}
// ...
}
Avez-vous vraiment besoin d'ajouter des définitions de service à services.yaml pour les classes de fournisseurs tiers?
Non, ne fais pas ça. Ma suggestion personnelle est la suivante: ne prolongez pas EntityRepository
. Déjà. Vous ne voulez pas que l'interface de votre référentiel ait une méthode comme createQuery
ou flush
. Au moins, vous ne voulez pas cela si vous considérez un référentiel comme une collection d'objets. Si vous prolongez EntityRepository
, vous aurez une abstraction qui fuit.
Au lieu de cela, vous pouvez injecter le EntityManager
à l'intérieur de votre référentiel, et c'est tout:
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.
}
Aucune autre étape n'est requise.