Nice programing

Symfony의 서비스에 저장소를 삽입하는 방법은 무엇입니까?

nicepro 2020. 10. 20. 08:10
반응형

Symfony의 서비스에 저장소를 삽입하는 방법은 무엇입니까?


두 개의 개체를 ImageService. 그중 하나는의 인스턴스이며 Repository/ImageRepository다음과 같이 표시됩니다.

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

그렇다면 내 services.yml에서 어떻게 선언합니까? 서비스는 다음과 같습니다.

namespace Mycompany\MainBundle\Service\Image;

use Doctrine\ODM\MongoDB\DocumentRepository;

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);
    }
}

다음은 나와 같은 Google 사용자를위한 정리 된 솔루션입니다.

업데이트 : 다음은 Symfony 2.6 이상 솔루션입니다.

services:

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

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

더 이상 사용되지 않는 솔루션 (Symfony 2.5 이하) :

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"

링크를 찾았고 이것은 나를 위해 일했습니다.

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%

각 저장소를 서비스로 정의하지 않으려는 경우 버전부터 2.4다음을 수행 할 수 있습니다. ( default는 엔티티 관리자의 이름입니다.)

@=service('doctrine.orm.default_entity_manager').getRepository('MycompanyMainBundle:Image')

2017 년과 Symfony 3.3+ 는 이것을 훨씬 더 간단하게 만들었습니다. Symfony 4.x에서도 동일합니다.

더 일반적인 설명 내 게시물 How to use Repository with Doctrine as Service in Symfony확인하십시오 .

코드에서해야 할 일은 SOLID 패턴 중 하나 인 상속보다 합성을 사용하는 것입니다 .

1. 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. PSR-4 기반 자동 등록으로 구성 등록 추가

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

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

3. 이제 생성자 주입을 통해 모든 종속성을 추가 할 수 있습니다.

use MycompanyMainBundle\Repository\ImageRepository;

class ImageService
{
    public function __construct(ImageRepository $imageRepository)
    {
        $this->imageRepository = $imageRepository;
    }
}

토마스 Votruba 응답이 @에 따라 내 경우 기지에서 질문 나는 다음과 같은 방법을 제안한다 :

어댑터 접근

상속없이

  1. 일반 어댑터 ​​클래스를 만듭니다.

    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. 그런 다음 foreach 엔터티 서비스를 정의합니다. 예를 들어 제 경우에는 다음을 정의합니다. (심포니 서비스를 정의하기 위해 PHP를 사용합니다.)

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

상속으로

  1. 위에서 언급 한 동일한 1 단계

  2. Extend the RepositoryServiceAdapter class for example:

    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. Register service:

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

Either the case you have a good testable way to function tests your database beavior also it aids you on mocking in case you want to unit test your service without the need to worry too much on how to do that. For example, let us suppose we have the following service:

//Namespace definitions etc etc

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

And the RepositoryServiceAdapter adapts the following repository:

//Namespace definitions etc etc

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

Testing

So you can easily mock/hardcode/emulate the behavior of the method search defined in SomeRepository by mocking aither the RepositoryServiceAdapter in non-inheritance approach or the ContactEmailRepositoryServiceAdapter in the inheritance one.

The Factory Approach

Alternatively you can define the following factory:

namespace AppBundle\ServiceFactories;

use Doctrine\ORM\EntityManagerInterface;

class RepositoryFactory
{
  /**
  * @param EntityManagerInterface $entityManager The doctrine entity Manager
  * @param String $entityName The name of the entity
  * @return Class
  */
  public static function repositoryAsAService(EntityManagerInterface $entityManager,$entityName)
  {
    return $entityManager->getRepository($entityName);
  }
}

And then Switch to php service annotation by doing the following:

Place this into a file ./app/config/services.php (for symfony v3.4, . is assumed your ptoject's root)

use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
$definition = new Definition();

$definition->setAutowired(true)->setAutoconfigured(true)->setPublic(false);

// $this is a reference to the current loader
$this->registerClasses($definition, 'AppBundle\\', '../../src/AppBundle/*', '../../src/AppBundle/{Entity,Repository,Tests,Interfaces,Services/Adapters/RepositoryServiceAdapter.php}');


$definition->addTag('controller.service_arguments');
$this->registerClasses($definition, 'AppBundle\\Controller\\', '../../src/AppBundle/Controller/*');

And cange the ./app/config/config.yml (. is assumed your ptoject's root)

imports:
    - { resource: parameters.yml }
    - { resource: security.yml }
    #Replace services.yml to services.php
    - { resource: services.php }

#Other Configuration

Then you can clace the service as follows (used from my example where I used a Dummy entity named Item):

$container->register(ItemRepository::class,ItemRepository::class)
  ->setFactory([new Reference(RepositoryFactory::class),'repositoryAsAService'])
  ->setArguments(['$entityManager'=>new Reference('doctrine.orm.entity_manager'),'$entityName'=>Item::class]);

Also as a generic tip, switching to php service annotation allows you to do trouble-free more advanced service configuration thin one above. For code snippets use a special repository I made using the factory method.

참고URL : https://stackoverflow.com/questions/12223176/how-to-inject-a-repository-into-a-service-in-symfony

반응형