0

Is it possible to put some services in to another container which will be narrowed to a specific set o services? Or to separate some specific services to some kind of sub-container? I am asking this question because I need to inject a set of services into another service, and putting a whole container into service is , I belive, bad idea. Of course I can create a property in my service class for all services that I want to inject, but this is a solution that I am trying to avoid.

I will appreciate any help, and if you need more info about the problem just ask.

4

2 に答える 2

1

基本的に、特別な名前で「タグ付けされた」いくつかのサービスを記述することで、DIC を使用できます。
このためには、サービスをファイルに定義し (DIC 仕様に従って)、特定の方法でタグ付けする必要があります (この場合、コードは説明のために Sonata Admin Bundle によって取得されます)。

# MyBundle/Resources/config/admin.yml
services:
    sonata.admin.tag:
        class: YourNS\AdminBundle\Admin\BlogAdmin
        tags:
            - { name: sonata.admin, manager_type: orm, group: posts, label: "Blog" }
        arguments:
            - ~
            - YourNS\AdminBundle\Entity\Course
            - 'SonataAdminBundle:CRUD'
        calls:
            - [ setTranslationDomain, [YourNSAdminBundle]]

この場合、sonata.admin.tagタグでタグ付けされたというサービスを定義していますsonata.admin。タグ名を付け
て、それらを何十個も定義できます。sonata.admin.tag

これが完了したら、 file である「特別な」ファイル ( DependencyInjection[慣習のために] バンドルのフォルダーに配置する) を作成する必要がありCompilerPassます
CompilerPass ファイルとは何ですか?

コンパイラ パスは、サービス コンテナに登録されている他のサービス定義を操作する機会を提供します。セクション「タグ付きサービスの操作」)。

これはまさにあなたが必要とするものです!

次に、(この特定の例では)でタグ付けされたサービスを(このファイルで)検索する必要がありますsonata.admin

class AddDependencyCallsCompilerPass implements CompilerPassInterface
{
  /**
  * {@inheritDoc}
  */
    public function process(ContainerBuilder $container)
    {
        $groupDefaults = $admins = $classes = array();

        $pool = $container->getDefinition('sonata.admin.pool');

        foreach ($container->findTaggedServiceIds('sonata.admin') as $id => $tags) {
            foreach ($tags as $attributes) {
                $definition = $container->getDefinition($id);

                $arguments = $definition->getArguments();

                if (strlen($arguments[0]) == 0) {
                    $definition->replaceArgument(0, $id);
                }

                if (strlen($arguments[2]) == 0) {
                    $definition->replaceArgument(2, 'SonataAdminBundle:CRUD');
                }

                $this->applyConfigurationFromAttribute($definition, $attributes);
                $this->applyDefaults($container, $id, $attributes);

                $arguments = $definition->getArguments();

                $admins[] = $id;
                //other logic here
                $pool->addMethodCall('setAdminClasses', array($classes));

ここでわかるように、sonata.admin( $container->findTaggedServiceIds('sonata.admin')) でタグ付けされたサービスを検索し、それら (この場合は、sonata 管理バンドルに固有のもの)$poolContainerBuilder

ここで、CompilerPass をバンドル ファイル (バンドルをアプリケーションに登録する前に作成するファイル) に登録する必要があります。

class SonataAdminBundle extends Bundle
{
    /**
    * {@inheritDoc}
    */
    public function build(ContainerBuilder $container)
    {
        $container->addCompilerPass(new AddDependencyCallsCompilerPass());
    }
}

これで、このバンドル専用のある種のサービスが登録されました。サービス工場はより志向的です

Symfony2 のサービス コンテナーは、オブジェクトの作成を制御する強力な方法を提供し、コンストラクターに渡される引数を指定したり、メソッドを呼び出したりパラメーターを設定したりできるようにします。ただし、オブジェクトを作成するために必要なすべてが提供されない場合があります。

または、サービスのインスタンス化の「エントリ ポイント」のように表示します。

于 2013-05-24T13:40:21.197 に答える
0

コンテナー全体を注入することは、パフォーマンスとテスト容易性の理由から、実際にはお勧めできません。

すべての依存関係のコンストラクターまたはゲッター/セッターの注入があなたが望む方法ではない場合...

...サービス ファクトリーはあなたが探しているものです。

このようにして、他のサービスを保持するサービスを構築し、このサービスのみを注入できます。

それはあなたが話している「サブコンテナ」のようなものです。

于 2013-05-24T07:14:49.607 に答える