programing

Symfony에서 저장소에 주입하려면 어떻게 해야 합니까?

goodsources 2022. 10. 11. 22:53
반응형

Symfony에서 저장소에 주입하려면 어떻게 해야 합니까?

나는두개의물체를 주입해야 합니다에 두 개체 도입해야 합니다.ImageService그 중 하나가바로 그 예다. 그들 중 하나는 인스턴스.Repository/ImageRepository저는 이런면:이런생각이 듭니다.

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

그럼 서비스에서는 어떻게 선언해야 하나요?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);
    }
}

다음은 저처럼 구글에서 온 사람들을 위한 정리된 솔루션입니다.

업데이트: 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회사 매니저의 이름):.A엔티티매니저의 이름입니다 cm이다.

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

Symfony 3.3, 4 및 5는 이를 훨씬 단순하게 합니다.

보다 일반적인 설명은 Symfony에서 서비스로서의 독트린을 사용저장소 사용 방법참조하십시오.

코드에 따르면 SOLID 패턴 중 하나인 상속 위에 컴포지션을 사용하면 됩니다.

1.독트린에 직접 의존하지 않고 자체 저장소 만들기

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

제 경우 @Tomash 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 entity 예를 들어 서비스를 정의합니다(예를 들어 php를 사용하여 symfony 서비스를 정의합니다).

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

상속과 함께

  1. 위의 순서 1과 동일

  2. 그 확장을 확장하다.RepositoryServiceAdapter예를 들어 수업예를들어 다음과 같습니다.

    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. 서비스 등록:

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

어느 경우든 테스트 가능한 방법으로 데이터베이스를 테스트하는 것이 좋습니다.또, 그 방법에 대해 크게 걱정할 필요 없이, 서비스를 유닛으로 테스트하고 싶은 경우에 대해서도, 조롱하는 것이 도움이 됩니다.예를 들어 다음과 같은 서비스가 있다고 가정합니다.

//Namespace definitions etc etc

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

Repository Service Adapter는 다음 저장소를 채택합니다.

//Namespace definitions etc etc

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

테스트

그래서 너는 쉽게 법 따라서 메서드의 동작을 쉽게 조롱/하드코드/에뮬레이트할 수 있습니다의 행동 mock/hardcode/emulate 수 있다.search에 정의되어 있다에 정의된 것이다.SomeRepository을 조롱하는 것에 의해 aither은 어느 쪽도 조롱이든RepositoryServiceAdapternon-inheritance 접근 또는비준거성 접근법 또는에서.ContactEmailRepositoryServiceAdapter상속에서는.상속받은것 중 하나.

팩토리 어프로치

또는 다음 팩토리를 정의할 수도 있습니다.

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

그런 다음 다음을 수행하여 php 서비스 주석으로 전환합니다.

「」에 격납해 주세요../app/config/services.php(symfony v3.4의 경우,.putject의 루트로 간주됩니다.)

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/*');

그리고,./app/config/config.yml(.putject의 루트로 간주됩니다.)

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

#Other Configuration

그런 다음 다음과 같이 서비스를 정리할 수 있습니다(이 예에서는 Dummy 엔티티 이름에서 사용).Item):

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

일반적인 힌트로서 전환하기 위해서phpservice annotation을 사용하면 위의 고급 서비스 구성 씬을 문제 없이 수행할 수 있습니다.코드 스니펫의 경우는, 를 사용해 작성한 특별한 저장소를 사용합니다.factory방법.

Symfony 5의 경우 services.yml이 없어도 의존관계를 주입할 수 있습니다.

  1. 서비스 컨스트럭터에 엔티티 매니저 삽입
private $em;

public function __construct(EntityManagerInterface $em)
{
    $this->em = $em;
}
  1. 다음으로 저장소를 가져옵니다.

$this->em->getRepository(ClassName: 클래스)

ClassName을 엔티티 이름으로 바꿉니다.

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

반응형