まえがき
最初に、Symfony2のアーキテクチャについて簡単に説明します。 アプリケーションの中核は、コンポーネント(コンポーネント)で構成されます。コンポーネント(コンポーネント)は、互いに独立した要素であり、特定の機能を実行します。 アプリケーションのビジネスロジックは、いわゆる バンダ 。 Symfony2の組み込みコンポーネントとともに、サードパーティベンダーの他のライブラリコンポーネント(人気のあるZendを含む)を、オートローダーに正しく登録することを忘れずに接続できます。 原則として、Symfony2のコアとともに、 Twig (テンプレートエンジン)、 Doctrine2 (ORM)、 SwiftMailer (メーラー)などのコンポーネントが提供されます。
サービス指向アーキテクチャ
機能を独立したサービスとして際立つモジュールに分割するイデオロギーは、一般にサービス指向アーキテクチャー (SOA)と呼ばれます。 Symfony2の基盤です。
依存性注入と制御の反転
OOPを使用するアプリケーションでは、開発者はオブジェクトを操作および操作します。 各オブジェクトは特定の機能(サービス)を実行することを目的としており、他のオブジェクトがその内部にカプセル化されている可能性があります。 親オブジェクトが子孫インスタンスの状態を制御する必要があるため、あるオブジェクトが別のオブジェクトに依存していることがわかります。 Dependency Injection(DI)パターンは、この必要性を排除し、外部コードへの依存関係管理を提供するように設計されています。 つまり オブジェクトは常に、別のオブジェクト(子孫)の既製のインスタンスで動作し、このオブジェクトの作成方法、作成者、および他の依存関係が存在するかどうかを知りません。 親オブジェクトは、通常、コンストラクターまたはセッターメソッドを介して、依存オブジェクトを置き換えるためのメカニズムを提供するだけです。 この制御の移行は、制御の反転と呼ばれます。 反転は、オブジェクト自体が子孫オブジェクトの状態を制御しなくなることです。
Symfony2のDependency Injectionコンポーネントは、コンテナに依存し、登録されたすべてのサービスを管理し、それらの間の関係を監視し、サービスインスタンスを作成し、ルックアップメカニズムを使用します。
IoCコンテナー
DIコンポーネントは、サービスオブジェクト間の依存関係と、管理できるサービスを知る必要があります。 これを行うために、Symfony2にはContainerBuilderがあります。これは、xmlマップまたはバンドル内の直接的な依存関係の形成に基づいて形成されます。 これはsymfony2でどのように起こりますか。 アプリケーションにApp \ HelloBundleがあるとします。 コンテナを作成し、そのサービスで補完するには(フレームワークレベルで、コンテナはすでに存在し、標準バンドルで定義されたサービスで満たされます)、バンドルルートディレクトリにDependencyInjectionディレクトリを作成し、\ Symfony \ Component \ HttpKernel \ DependencyInjection \ Extensionクラスのロードメソッドを再定義する必要があります(一致する) Symfony2ルールは、クラスAppHelloBundleExtension、つまり[namespace] [bundle name] Extension)を呼び出す必要があります。
# App\HelloBundle\DependencyInjection\AppHelloBundleExtension.php <?php namespace App\HelloBundle\DependencyInjection; use Symfony\Component\HttpKernel\DependencyInjection\Extension; class AppHelloBundleExtension extends Extension { public function load(array $configs, ContainerBuilder $container) { ... } }
アプリケーションサービス
既にAppHelloBundleExtensionを入手したら、サービスの追加を開始できます。 この場合、サービスオブジェクト自体ではなく、その定義(定義)のみで操作していることに注意してください。 このコンテキストでは、コンテナ自体はまだ欠落しているため、定義に基づいてのみ形成されます。
# App\HelloBundle\DependencyInjection\AppHelloBundleExtension.php public function load(array $configs, ContainerBuilder $container) { $definition = new Definition('HelloBundle\\SomePrettyService'); $container->addDefinition($definition); }
このような「手動」コード生成に加えて、特定のルールに従って作成されたxmlサービスマップのインポートを使用できます。 明らかに、より便利で視覚的です。
# App\HelloBundle\DependencyInjection\AppHelloBundleExtension.php public function load(array $configs, ContainerBuilder $container) { $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services.xml'); }
ただし、定義を作成する両方の方法を使用することを妨げるものは何もありません。
# App\HelloBundle\DependencyInjection\AppHelloBundleExtension.php public function load(array $configs, ContainerBuilder $container) { $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services.xml'); $definition = $container->getDefinition('some.pretty.service'); // ... // do something with $definition // ... }
これは、定義構造がxml-fileで指定されており、たとえば構成ファイルからの必要な引数の値が定義のExtensionで置き換えられている場合に便利です。 独自の構成の作成は、現在の記事の範囲をわずかに超えており、後で検討される可能性があります。 現時点では、構成からのデータを含むコレクションがあると想定されています。
次に、xmlで将来のサービス定義を作成する方法を見てみましょう。 ファイルのルート構造は次のとおりです
< container xmlns ="http://symfony.com/schema/dic/services" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://symfony.com/schema/dic/services symfony.com/schema/dic/services/services-1.0.xsd" >
< parameters >
< parameter > ... </ parameter >
...
</ parameters >
< services >
< service > ... </ service >
...
</ services >
</ container >
* This source code was highlighted with Source Code Highlighter .
各サービス定義は、サービスタグによって定義されます。 次の属性が提供されます。
- id-サービスの名前(このサービスをコンテナから取得できるもの)
- class-サービスクラスの名前。新しい構成体を通じて作成される場合(サービスがファクトリーを通じて作成される場合、クラス名はインターフェースまたは抽象クラスへのリンクになります)
- 範囲
- public-trueまたはfalse-サービスの可視性
- 合成-trueまたはfalse
- abstract-trueまたはfalse-指定されたサービス定義が抽象であるかどうか、つまり 他のサービスの定義に使用するテンプレート
- factory-class-静的メソッド呼び出しのファクトリクラスの名前
- factory-service-パブリックメソッドを呼び出すための既存のファクトリサービスの名前
- factory-method-コンテナがアクセスしているファクトリメソッドの名前
- 別名-サービス別名
- 親
パラメータ属性
- タイプ
- id
- 鍵
- 無効
次の要素は、サービスタグ内にネストできます。
< argument />
< tag />
< call />
* This source code was highlighted with Source Code Highlighter .
argument-パラメーターとして引数を渡します。既存のサービスへの参照または引数のコレクションです。
tag-サービスに割り当てられたタグ。
call-初期化後にサービスメソッドを呼び出します。 メソッドが呼び出されると、渡されたパラメーターが引数argumentタグを使用してリストされます。
属性とタグの値(クラス名など)は、ほとんどの場合パラメーターに入れられ、このパラメーターの属性またはタグへの置換を使用します。 パラメーターは、先頭と末尾に%記号が存在することで常に区別できます。 例えば
< parameters >
< parameter key ="some_service.class" > App\HelloBundle\Service </ parameter >
</ parameters >
< services >
< service id ="some_service" class ="%some_service.class%" />
</ services >
* This source code was highlighted with Source Code Highlighter .
この場合、すべてのパラメーターを1か所にリストしてから、サービス定義で複数回使用すると便利です。
サービス定義の例
上記でより明確に説明した例を、例で表すことができます。
< service id ="some_service_name" class ="App\HelloBundle\Service\Class" >
< argument > some_text </ argument >
< argument type ="service" id ="reference_service" /><! -- -- >
< argument type ="collection" >
< argument key ="key" > value </ argument >
</ argument >
< call method ="setRequest" >
< argument type ="service" id ="request" />
</ call >
</ service >
* This source code was highlighted with Source Code Highlighter .
上記のコンテナサービスは、最初にアクセスされたときに次のようになります
// $referenceService = ... ; $request = ... ; $service = new App\HelloBundle\Service\Class('some_text', $referenceService, array('key' => 'value')); $service->setRequest($request);
同じことですが、Symfony2の定義では
# App\HelloBundle\DependencyInjection\AppHelloBundleExtension.php public function load(array $configs, ContainerBuilder $container) { $definition = new Definition('App\HelloBundle\Service\Class'); $definition->addArgument('some_text'); $definition->addArgument(new Reference('reference_service')); $definition->addArgument(array('key' => 'value')); $definition->addMethodCall('setRequest', array(new Reference('request'))); $container->setDefinition('some_service_name', $definition); }
このサービスは、たとえば次のようなMVCコントローラーで取得できます。
$this->container->get('some_service_name');
サービス定義を作成するより具体的な例は、Symfony2カーネルに付属の標準バンドルにあると思います。
おわりに
結論として、Symfony2のサービスコンテナは非常に便利であり、アプリケーションに必要なすべてのサービスを一度設定し、それらを意図した目的に使用することができます。 Symfony2には、サービス定義を含む「スマートな」キャッシュシステムがあるため、追加または変更するたびにキャッシュをクリアすることを忘れないでください。
関連リンク
Martin Fawler:コントロールコンテナーの反転と依存性注入パターン
依存性注入
制御反転(制御反転)
Symfony2-サービスコンテナー