Comment injecter un dépôt dans un service en Symfony?

je dois injecter deux objets dans ImageService . L'un d'eux est une instance de Repository/ImageRepository , que j'obtiens comme ceci:

$image_repository = $container->get('doctrine.odm.mongodb')
    ->getRepository('MycompanyMainBundle:Image');

alors comment puis-je déclarer cela dans mes services.yml? Voici le service:

namespace MycompanyMainBundleServiceImage;

use DoctrineODMMongoDBDocumentRepository;

class ImageManager {
    private $manipulator;
    private $repository;

    public function __construct(ImageManipulatorInterface $manipulator, DocumentRepository $repository) {
        $this->manipulator = $manipulator;
        $this->repository = $repository;
    }

    public function findAll() {
        return $this->repository->findAll();
    }

    public function createThumbnail(ImageInterface $image) {
        return $this->manipulator->resize($image->source(), 300, 200);
    }
}
69
demandé sur Matthieu Napoli 2012-09-01 02:25:07

5 réponses

Voici une solution nettoyée pour ceux qui viennent de Google comme moi:

mise à Jour: ici, c'est le Symfony 2.6 (et plus) solution:

services:

    myrepository:
        class: Doctrine\ORM\EntityRepository
        factory: ["@doctrine.orm.entity_manager", getRepository]
        arguments:
            - MyBundle\Entity\MyClass

    myservice:
        class: MyBundle\Service\MyService
        arguments:
            - "@myrepository"

solution dépréciée (Symfony 2,5 et moins):

services:

    myrepository:
        class: Doctrine\ORM\EntityRepository
        factory_service: doctrine.orm.entity_manager
        factory_method: getRepository
        arguments:
            - MyBundle\Entity\MyClass

    myservice:
        class: MyBundle\Service\MyService
        arguments:
            - "@myrepository"
99
répondu Matthieu Napoli 2016-03-07 14:13:45

j'ai trouvé ce lien et cela a fonctionné pour moi:

parameters:
    image_repository.class:            Mycompany\MainBundle\Repository\ImageRepository
    image_repository.factory_argument: 'MycompanyMainBundle:Image'
    image_manager.class:               Mycompany\MainBundle\Service\Image\ImageManager
    image_manipulator.class:           Mycompany\MainBundle\Service\Image\ImageManipulator

services:
    image_manager:
        class: %image_manager.class%
        arguments:
          - @image_manipulator
          - @image_repository

    image_repository:
        class:           %image_repository.class%
        factory_service: doctrine.odm.mongodb
        factory_method:  getRepository
        arguments:
            - %image_repository.factory_argument%

    image_manipulator:
        class: %image_manipulator.class%
44
répondu ChocoDeveloper 2012-09-01 00:31:40

dans le cas où si vous ne voulez pas définir chaque dépôt comme un service, à partir de la version 2.4 vous pouvez faire ce qui suit, ( default est un nom du gestionnaire d'entité):

@=service('doctrine.orm.default_entity_manager').getRepository('MycompanyMainBundle:Image')
39
répondu b.b3rn4rd 2014-09-02 05:20:05

2017 et Symfony 3.3+ fait ce beaucoup plus simple.

Vérifier mon post Comment utiliser un Référentiel avec la Doctrine de Service dans Symfony pour une description plus générale.

à votre code, Tout ce que vous devez faire est d'utiliser composition sur héritage - un des modèles solides.

1. Créer son propre dépôt sans dépendance directe sur Doctrine

<?php

namespace MycompanyMainBundle\Repository;

use Doctrine\ORM\EntityManagerInterface;
use MycompanyMainBundle\Entity\Image;

class ImageRepository
{
    private $repository;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->repository = $entityManager->getRepository(Image::class);
    }

    // add desired methods here
    public function findAll()
    {
        return $this->repository->findAll();
    }
}

2. Ajouter enregistrement de configuration avec PSR-4 basé autoregistration

# app/config/services.yml
services:
    _defaults:
        autowire: true

    MycompanyMainBundle\:
        resource: ../../src/MycompanyMainBundle

3. Maintenant, vous pouvez ajouter n'importe quelle dépendance n'importe où via constructo injection

use MycompanyMainBundle\Repository\ImageRepository;

class ImageService
{
    public function __construct(ImageRepository $imageRepository)
    {
        $this->imageRepository = $imageRepository;
    }
}
4
répondu Tomáš Votruba 2017-10-21 11:36:14

dans mon cas se base sur @Tomáš Votruba réponse et cette question je propose les approches suivantes:

Sans Héritage

  1. créer une classe D'Adaptateur Générique:

    namespace AppBundle\Services;
    use Doctrine\ORM\EntityManagerInterface;
    
    class RepositoryServiceAdapter
    {
        private $repository=null;
    
        /**
        * @param EntityManagerInterface the Doctrine entity Manager
        * @param String $entityName The name of the entity that we will retrieve the repository
        */
        public function __construct(EntityManagerInterface $entityManager,$entityName)
        {
            $this->repository=$entityManager->getRepository($entityName)
        }
    
        public function __call($name,$arguments)
        {
          if(empty($arrguments)){ //No arguments has been passed
            $this->repository->$name();
          } else {
            //@todo: figure out how to pass the parameters
            $this->repository->$name(...$argument);
          }
        }
    }
    
  2. Ensuite chaque entité définir un service, par exemple dans mon cas de définir un (j'utilise php pour définir les services symfony):

     $container->register('ellakcy.db.contact_email',AppBundle\Services\Adapters\RepositoryServiceAdapter::class)
      ->serArguments([new Reference('doctrine'),AppBundle\Entity\ContactEmail::class]);
    

Avec Héritage

  1. même étape 1 mentionnée ci-dessus

  2. étendre la classe RepositoryServiceAdapter par exemple:

    namespace AppBundle\Service\Adapters;
    
    use Doctrine\ORM\EntityManagerInterface;
    use AppBundle\Entity\ContactEmail;
    
    class ContactEmailRepositoryServiceAdapter extends RepositoryServiceAdapter
    {
      public function __construct(EntityManagerInterface $entityManager)
      {
        parent::__construct($entityManager,ContactEmail::class);
      }
    }
    
  3. service du Registre:

    $container->register('ellakcy.db.contact_email',AppBundle\Services\Adapters\RepositoryServiceAdapter::class)
      ->serArguments([new Reference('doctrine')]);
    

soit le cas où vous avez une bonne façon testable de fonction teste votre base de données beavior aussi il aide vous sur la moquerie dans le cas où vous voulez tester votre service sans avoir à vous soucier trop sur la façon de le faire. Par exemple, supposons que nous ayons le service suivant:

//Namespace definitions etc etc

class MyDummyService
{
  public function __construct(RepositoryServiceAdapter $adapter)
  {
    //Do stuff
  }
}

et le Repoitoryserviceadapter adapte le dépôt suivant:

//Namespace definitions etc etc

class SomeRepository extends \Doctrine\ORM\EntityRepository
{
   public function search($params)
   {
     //Search Logic
   }
}

de sorte que vous pouvez facilement moquer / hardcode / émuler le comportement de la méthode search défini dans SomeRepository en se moquant soit le RepositoryServiceAdapter en non-héritage approche ou le ContactEmailRepositoryServiceAdapter dans l'héritage.

0
répondu Dimitrios Desyllas 2018-10-06 10:09:43