2014-09-11 3 views
0

필자가 작성한 여러 구성 요소를 사용하는 Symfony 응용 프로그램 용 번들을 작성하고 있습니다. MyAppBundle 번들을 호출합니다.번들이 아닌 패키지에 Symfony2 서비스 정의하기

내 번들이 사용하는 구성 요소는 Symfony에 의존하지 않지만 각각의 개별 패키지에있는 services.yml 파일 내에서 정의되는 각 구성 요소에 대한 Symfony 서비스 세트를 정의 할 수 있기를 바랍니다 - 그러나 나는이 패키지들이 완전히 날아가는 번들이되기를 원하지 않는다.

왜? 패키지를 Symfony 프레임 워크에 종속시키지 않기를 원하기 때문에 패키지를 Symfony 번들로 구성하지 않아도되고 단일 MyAppBundle을 등록하여 응용 프로그램에 필요한 모든 서비스를 등록 할 수 있기를 원합니다. 필자가 원한다면 무관 한 Symfony 앱에서 이러한 컴포넌트의 서비스를 사용할 수있는 유연성을 제공한다. 이것들을 풀 번들로 만들었다면 AppKernel에서 각 번들을 개별적으로로드해야 할 것입니다.

이 쉬워야한다 - 난 그냥 컨테이너 확장 구축하는 데 필요한 문서에 따라 : 자사의 서비스 정의를로드

그래서 내 구성 요소에 대한 컨테이너 확장을 http://symfony.com/doc/current/book/service_container.html#importing-configuration-via-container-extensions을 :

namespace MyComponent; 

class MyComponentExtension extends \Symfony\Component\DependencyInjection\Extension\Extension 
{ 

    public function load(array $configs, ContainerBuilder $container) 
    { 
     $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); 
     $loader->load('services.yml'); 
    } 

} 

I을 MyAppBundle에서이 확장을 어떻게로드 할 수 있는지 확실하지 않습니까? 다른 번들에서 확장을로드하는 방법에 대한 정보는 거의없는 것 같습니다. 어쩌면이 일을하는 것이 권장되는 방법은 아니지만 위에서 설명한 이유 때문에 필자의 유스 케이스가 정당하다고 생각합니다.

내 최고의 시도는 지금까지 MyAppBundle에서 MyComponentExtension로드에서입니다 :

namespace MyAppBundle; 

class MyAppBundle extends Bundle 
{ 

    public function build(ContainerBuilder $container) 
    { 
     $extensions = array(
      new MyComponentExtension(), 
      new MyOtherComponentExtension() 
     ); 
     $aliases = array(); 
     foreach($extensions as $extension) { 
      $container->registerExtension($extension); 
      $aliases[] = $extension->getAlias(); 
     } 
     $container->addCompilerPass(new MergeExtensionConfigurationPass($aliases)); 
    } 

} 

은 "addCompilerPass"비트는 내가 찾을 수있는 작은 정보에서 수집되었고, 나는 그것이 잘못 상당히 확신합니다. 이렇게하면 MyComponentExtension에서 제공하는 서비스에 액세스 할 수 없습니다. 나는 정의가 콘테이너에 제대로 컴파일되는지 확인해야하지만 확실하지는 않다. 확신 할 수 없다.

답변

0

커플 링에는 하드 커플 링과 소프트 커플 링의 두 가지 유형이 있습니다. 그렇다면 감 결합이 있습니다. 디커플링

당신이 번들에서 구성 요소를 분리

, 당신이 중 하나는 공통 인터페이스 (http://en.wikipedia.org/wiki/Dependency_inversion_principle)에 따라 각 부분이있다.

또는 단방향 종속성을 가질 수 있습니다. 이 경우 번들은 구성 요소에 종속됩니다. Symfony Framework Bundle은 Symfony 구성 요소에 의존합니다.

첫 번째 예제에서는 구성을 사용하여 사용할 클래스를 정의합니다. 그런 다음 번들에 포함 된 서비스를 구성 요소의 클래스로 정의합니다. Symfony Framework Bundle이하는 일입니다.

소프트 커플 링

(당신이 간접적으로 하드 의존성이되는 후, 그것을 사용하려고하지 않는 한) 라이브러리 참조 다른 (또는 다른 추상화가), 그러나 그것을 필요로하지 않을 때입니다.제공 할 리소스가없는 경우 생략되는 추가 기능.

예를 들면, Symfony에 대한 지원을 제공하지만 필요하지는 않습니다.

예를 들어 Symfony\Bridge\Doctrine\DependencyInjection\AbstractDoctrineExtension을 살펴보십시오.

일반적인 전략은 추상 확장을 만든 다음 번들에서 재정의하는 것입니다. 추가 통합이 필요한 경우 번들은 구성 요소의 일부를 대체 할 수 있습니다 (http://en.wikipedia.org/wiki/Liskov_substitution_principle).

이상적인 상황 어느 쪽이든 자체 (http://en.wikipedia.org/wiki/Single_responsibility_principle)를 사용할 수있는 구성이며, 단지 서비스로 부트 스트랩 심포니 사용.

서 분리 된

Bundle => depends on => Component 
Component depends on nothing 

소프트 종속성

Bundle => depends on => Component 
Component -> supports -> Symfony 

당신은 무엇을 생각하지 않을해야 할 것은 양방향 의존성을 만드는 것입니다. 그것은 각각 정적으로 서로 의존하는 부분입니다. 방법에 응답

편집 :

할 수 있습니다,하지만 당신은 나에게 비밀 유지됩니다 필요 이유에.

class MyAppBundle extends Bundle 
{ 
    /** 
    * Override extension getter. 
    */ 
    public function getContainerExtension() 
    { 
     if(null === $this->extension) { 
      $this->extension = new My\Component\Extension(); 
     } 

     return $this->extension; 
    } 
} 
+0

감사합니다. 실제로 MyComponentExtension은 Symfony에 대한 의존성이 적기를 원하지만, MyAppBundle에서 ComponentExtension을 올바르게 등록 할 수있는 방법을 알려주지 않습니다. – Mike

+0

AbstractDoctrineExtension을 제공 한 예제에서 여전히 AppKernel 클래스에서 개별적으로로드해야하는 DoctrineBundle이 있어야합니다. MyAppBundle이 MyComponentExtension 자체를로드해야하므로 피하고자하는 상황입니다. – Mike

+0

예,하지만 Doctrine \ Bundle \ DoctrineBundle \ DependencyInjection \ DoctrineExtension은 브리지에서'AbstractDoctrineExtension'을 확장합니다. – Flosculus

0

너는 이것을 어렵게 만들 수도있다. MyAppExtension은 컴포넌트 라이브러리에서 services.yml을 쉽게로드 할 수 있습니다. 구성 요소 확장이 필요 없습니다.

class MyAppBundleExtension extends Extension 
{ 
    public function load(array $configs, ContainerBuilder $container) 
    { 
     $loader = new Loader\YamlFileLoader($container, 
      new FileLocator('path_to_component_library')); 
     $loader->load('services.yml'); 
    } 

구성 요소 라이브러리 경로를 얻는 것이 유일한 사소한 문제이지만 하드 코딩해도 문제가되지 않습니다.

그렇다면 실제로는 라이브러리에 브리지 번들을 만드는 것을 고려해야합니다. 정말 필요한 것은 Bundle 클래스, Extension 클래스 및 services.yml 파일뿐입니다. 도서관 자체가 그대로 유지 될 수 있습니다.

브리지는 Symfony 2 프레임 워크가 Twig 및 Doctrine과 같은 라이브러리에 액세스하는 데 사용하는 것입니다. 확실히 그들은 당신의 도서관에서도 잘 작동 할 것입니다. 다음을보십시오 : vendor/symfony/monolog-bundle 예제.

+0

이것은 내가 결국 선택한 방법과 다소 비슷합니다. 내 구성 요소에 정적 로더 메서드를 사용하여 경로를 하드 코딩하는 것을 피했습니다. 브리지 번들을 만들지 않는 이유는 오직 하나의 번들을 내 AppKernel에로드하고 다른 종속 번들을 별도로로드 할 필요가 없기 때문입니다. – Mike

0

다음은 내가 결국 선택한 해결책입니다. 나는 정적 buildContainer 방법으로 MyComponent라고 내에서 로더 클래스를 생성 :

<?php 

namespace MyComponent; 

use Symfony\Component\Config\FileLocator; 
use Symfony\Component\DependencyInjection\ContainerBuilder; 
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; 

class MyComponentLoader 
{ 

    /** 
    * Loads component services into a container. 
    * 
    * @param ContainerBuilder $container 
    */ 
    public static function buildContainer(ContainerBuilder $container) 
    { 
     $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/Resources/config')); 
     $loader->load('services.yml'); 
    } 

} 

가 그럼 난 MyAppBundle 내 MyAppExtension에서 내 용기에 서비스로드 : 유익한 답변

<?php 

namespace MyAppBundle\DependencyInjection; 

use MyComponent\MyComponentLoader; 
use MyOtherComponent\MyOtherComponentLoader; 
use Symfony\Component\Config\FileLocator; 
use Symfony\Component\DependencyInjection\ContainerBuilder; 
use Symfony\Component\DependencyInjection\Extension\Extension; 
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; 

class SmartCloneExtension extends Extension 
{ 

    public function load(array $configs, ContainerBuilder $container) 
    { 
     MyComponentLoader::buildContainer($container); 
     MyOtherComponentLoader::buildContainer($container); 
    } 

} 
+0

이제는 컴포넌트가 Symfony 2에 의존하지 않는다는 자체 요구 사항을 위반했습니다. 조금 이상하게 보입니다. – Cerad

+0

이것은 단지 부드러운 의존성 일뿐입니다. MyComponentLoader 클래스는 symfony2 컨테이너에 종속적 인 buildContainer 메소드를 가지고 있지만 나머지 컴포넌트는 독립형으로 작동 할 수 있습니다. 나는 "교량"포장을 만들 수 있었다 그러나 여기 나의 목적을 위해 이것은 과잉 같이 보였다. – Mike

+0

물론 필요하지 않은데 왜 모든 의존성이 있습니까? 그것은 완벽하게 괜찮습니다. 그러나 나는 그것이 작동하도록하기 위해 당신이 의존성을 전혀 필요로하지 않는다는 것을 분명히하고 싶었습니다. 그리고 만약 당신이 의존성을 갖게된다면 하나의 번들 클래스를 추가하면 완전한 번들이 될 것입니다. 그것이 과잉 인 것처럼 보이지는 않습니다. 그러나 다시, 그것이 당신을 위해 일하는 한. – Cerad

관련 문제