サービスの定義

設定は、DIコンテナに個々のサービスをどのように組み立て、他の依存関係とどのように接続するかを教える場所です。Netteは、これを達成するための非常に明確でエレガントな方法を提供します。

NEON形式の設定ファイルのservicesセクションは、独自のサービスとその構成を定義する場所です。PDOクラスのインスタンスを表すdatabaseという名前のサービスを定義する簡単な例を見てみましょう:

services:
	database: PDO('sqlite::memory:')

上記の構成は、DIコンテナで次のファクトリメソッドになります:

public function createServiceDatabase(): PDO
{
	return new PDO('sqlite::memory:');
}

サービス名を使用すると、設定ファイルの他の部分で@サービス名の形式で参照できます。サービスに名前を付ける必要がない場合は、単に箇条書きを使用できます:

services:
	- PDO('sqlite::memory:')

DIコンテナからサービスを取得するには、サービス名をパラメータとしてgetService()メソッドを使用するか、サービスタイプをパラメータとしてgetByType()メソッドを使用できます:

$database = $container->getService('database');
$database = $container->getByType(PDO::class);

サービスの作成

ほとんどの場合、特定のクラスのインスタンスを作成するだけでサービスを作成します。例:

services:
	database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)

構成を他のキーで拡張する必要がある場合は、定義を複数行に分割できます:

services:
	database:
		create: PDO('sqlite::memory:')
		setup: ...

createキーにはエイリアスfactoryがあり、両方のバリアントが実際によく使用されます。ただし、createを使用することをお勧めします。

コンストラクタまたは作成メソッドの引数は、代わりにargumentsキーに記述することもできます:

services:
	database:
		create: PDO
		arguments: ['mysql:host=127.0.0.1;dbname=test', root, secret]

サービスは、クラスのインスタンスを単純に作成するだけでなく、静的メソッドや他のサービスのメソッドを呼び出すことによっても作成できます:

services:
	database: DatabaseFactory::create()
	router: @routerFactory::create()

単純化のために->の代わりに::が使用されていることに注意してください。表現手段を参照してください。これらのファクトリメソッドが生成されます:

public function createServiceDatabase(): PDO
{
	return DatabaseFactory::create();
}

public function createServiceRouter(): RouteList
{
	return $this->getService('routerFactory')->create();
}

DIコンテナは、作成されたサービスのタイプを知る必要があります。指定された戻り値の型を持たないメソッドを使用してサービスを作成する場合、このタイプを構成で明示的に指定する必要があります:

services:
	database:
		create: DatabaseFactory::create()
		type: PDO

引数

コンストラクタとメソッドに引数を渡す方法は、PHP自体と非常によく似ています:

services:
	database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)

読みやすくするために、引数を個別の行に分割できます。この場合、カンマの使用はオプションです:

services:
	database: PDO(
		'mysql:host=127.0.0.1;dbname=test'
		root
		secret
	)

引数に名前を付けることもでき、その順序を気にする必要はありません:

services:
	database: PDO(
		username: root
		password: secret
		dsn: 'mysql:host=127.0.0.1;dbname=test'
	)

一部の引数を省略してデフォルト値を使用するか、オートワイヤリングを使用してサービスを挿入する場合は、アンダースコアを使用します:

services:
	foo: Foo(_, %appDir%)

引数としてサービスを渡したり、パラメータを使用したり、その他多くのことができます。表現手段を参照してください。

Setup

setupセクションでは、サービスの作成時に呼び出すメソッドを定義します。

services:
	database:
		create: PDO(%dsn%, %user%, %password%)
		setup:
			- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)

これはPHPでは次のようになります:

public function createServiceDatabase(): PDO
{
	$service = new PDO('...', '...', '...');
	$service->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
	return $service;
}

メソッドの呼び出しに加えて、プロパティに値を渡すこともできます。配列への要素の追加もサポートされており、NEON構文と衝突しないように引用符で囲む必要があります:

services:
	foo:
		create: Foo
		setup:
			- $value = 123
			- '$onClick[]' = [@bar, clickHandler]

これはPHPコードでは次のようになります:

public function createServiceFoo(): Foo
{
	$service = new Foo;
	$service->value = 123;
	$service->onClick[] = [$this->getService('bar'), 'clickHandler'];
	return $service;
}

ただし、setupでは静的メソッドや他のサービスのメソッドを呼び出すこともできます。現在のサービスを引数として渡す必要がある場合は、@selfとして指定します:

services:
	foo:
		create: Foo
		setup:
			- My\Helpers::initializeFoo(@self)
			- @anotherService::setFoo(@self)

単純化のために->の代わりに::が使用されていることに注意してください。表現手段を参照してください。このようなファクトリメソッドが生成されます:

public function createServiceFoo(): Foo
{
	$service = new Foo;
	My\Helpers::initializeFoo($service);
	$this->getService('anotherService')->setFoo($service);
	return $service;
}

表現手段

Nette DIは、ほとんど何でも記述できる非常に豊富な表現手段を提供します。したがって、構成ファイルでパラメータを使用できます:

# パラメータ
%wwwDir%

# キーの下のパラメータ値
%mailer.user%

# 文字列内のパラメータ
'%wwwDir%/images'

さらに、オブジェクトを作成し、メソッドと関数を呼び出します:

# オブジェクトの作成
DateTime()

# 静的メソッドの呼び出し
Collator::create(%locale%)

# PHP関数の呼び出し
::getenv(DB_USER)

サービスを名前またはタイプで参照します:

# 名前によるサービス
@database

# タイプによるサービス
@Nette\Database\Connection

ファーストクラスの呼び出し可能構文を使用します:

# コールバックの作成、[@user, logout]に類似
@user::logout(...)

定数を使用します:

# クラス定数
FilesystemIterator::SKIP_DOTS

# グローバル定数はPHP関数constant()で取得します
::constant(PHP_VERSION)

メソッド呼び出しはPHPと同様に連鎖させることができます。ただし、単純化のために->の代わりに::が使用されます:

DateTime()::format('Y-m-d')
# PHP: (new DateTime())->format('Y-m-d')

@http.request::getUrl()::getHost()
# PHP: $this->getService('http.request')->getUrl()->getHost()

これらの式は、サービスの作成引数setupセクション、またはパラメータでどこでも使用できます:

parameters:
	ipAddress: @http.request::getRemoteAddress()

services:
	database:
		create: DatabaseFactory::create( @anotherService::getDsn() )
		setup:
			- initialize( ::getenv('DB_USER') )

特殊関数

構成ファイルでは、次の特殊関数を使用できます:

  • not() 値の否定
  • bool(), int(), float(), string() 指定された型へのロスレス型キャスト
  • typed() 指定された型のすべてのサービスの配列を作成します
  • tagged() 指定されたタグを持つすべてのサービスの配列を作成します
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

PHPの従来の型キャスト(例:(int))とは異なり、ロスレス型キャストは非数値に対して例外をスローします。

typed()関数は、指定された型(クラスまたはインターフェース)のすべてのサービスの配列を作成します。オートワイヤリングが無効になっているサービスは除外されます。カンマで区切って複数の型を指定することもできます。

services:
	- BarsDependent( typed(Bar) )

特定の型のサービスの配列は、オートワイヤリングを使用して自動的に引数として渡すこともできます。

tagged()関数は、特定のタグを持つすべてのサービスの配列を作成します。ここでも、カンマで区切って複数のタグを指定できます。

services:
	- LoggersDependent( tagged(logger) )

オートワイヤリング

autowiredキーを使用すると、特定のサービスのオートワイヤリングの動作に影響を与えることができます。詳細については、オートワイヤリングに関する章を参照してください。

services:
	foo:
		create: Foo
		autowired: false     # サービスfooはオートワイヤリングから除外されます

遅延サービス

遅延読み込みは、サービスが実際に必要になるまでその作成を延期する技術です。グローバル設定では、すべてのサービスに対して遅延作成を有効にすることができます。個々のサービスについては、この動作を上書きできます:

services:
	foo:
		create: Foo
		lazy: false

サービスが遅延として定義されている場合、DIコンテナから要求されると、特別なプレースホルダーオブジェクトが返されます。これは実際のサービスと同じように見え、動作しますが、実際の初期化(コンストラクタとセットアップの呼び出し)は、そのメソッドまたはプロパティのいずれかが最初に呼び出されたときにのみ行われます。

遅延読み込みは、ユーザー定義クラスにのみ使用でき、内部PHPクラスには使用できません。PHP 8.4以降が必要です。

タグ

タグは、サービスに追加情報を提供するために使用されます。サービスに1つ以上のタグを追加できます:

services:
	foo:
		create: Foo
		tags:
			- cached

タグは値を持つこともできます:

services:
	foo:
		create: Foo
		tags:
			logger: monolog.logger.event

特定のタグを持つすべてのサービスを取得するには、tagged()関数を使用できます:

services:
	- LoggersDependent( tagged(logger) )

DIコンテナでは、findByTag()メソッドを使用して特定のタグを持つすべてのサービスのリストを取得できます:

$names = $container->findByTag('logger');
// $names はサービス名とタグ値を含む配列です
// 例:['foo' => 'monolog.logger.event', ...]

Injectモード

inject: trueフラグを使用すると、injectアノテーションを持つパブリック変数とinject*()メソッドを介した依存関係の受け渡しが有効になります。

services:
	articles:
		create: App\Model\Articles
		inject: true

デフォルトでは、injectはPresenterに対してのみ有効化されます。

サービスの変更

DIコンテナには、組み込みまたはユーザー拡張機能を介して追加された多くのサービスが含まれています。これらのサービスの定義は、構成で直接変更できます。たとえば、通常はNette\Application\Applicationであるサービスapplication.applicationのクラスを別のものに変更できます:

services:
	application.application:
		create: MyApplication
		alteration: true

alterationフラグは情報提供であり、既存のサービスを変更しているだけであることを示します。

セットアップを追加することもできます:

services:
	application.application:
		create: MyApplication
		alteration: true
		setup:
			- '$onStartup[]' = [@resource, init]

サービスを上書きするときに、元の引数、セットアップ項目、またはタグを削除したい場合は、resetを使用します:

services:
	application.application:
		create: MyApplication
		alteration: true
		reset:
			- arguments
			- setup
			- tags

拡張機能によって追加されたサービスを削除したい場合は、次のようにします:

services:
	cache.journal: false
バージョン: 3.x