サービス定義

コンフィギュレーションは、DIコンテナに対して、個々のサービスの組み立て方や、他の依存関係との接続方法を指示する場所です。Netteは、これを実現するための非常に明確でエレガントな方法を提供します。

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

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

この設定により、DIコンテナのファクトリーメソッドは次のようになります:

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

サービス名は、設定ファイルの他の部分で参照できるようにするためのもので、@serviceName.サービス名を付ける必要がない場合は、単に箇条書きを使用できます:

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 セクションでは、サービスを作成する際に呼び出されるメソッドを定義します。

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

セットアップでは、静的メソッドや他のサービスのメソッドを呼び出すこともできます。現在のサービスを引数として渡す必要がある場合は、@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は、非常に豊富な表現機能を備えており、ほとんど何でも表現することができます。設定ファイルでは、パラメータを使うことができます:

# parameter
%wwwDir%

# value under a parameter key
%mailer.user%

# parameter within a string
'%wwwDir%/images'

また、オブジェクトを作成したり、メソッドや関数を呼び出したりすることもできます:

# create an object
DateTime()

# call a static method
Collator::create(%locale%)

# call a PHP function
::getenv(DB_USER)

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

# service by name
@database

# service by type
@Nette\Database\Connection

ファーストクラスの callable 構文を使用する:.{data-version:3.2.0}

# creating a callback, equivalent to [@user, logout]
@user::logout(...)

定数を使用する:

# class constant
FilesystemIterator::SKIP_DOTS

# global constant obtained by the PHP function constant()
::constant(PHP_VERSION)

Method calls can be chained, just like in PHP. For simplicity, instead of ->, we use :::

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

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

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

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%)
	)

(int) のような PHP の従来の型キャストと比較すると、 ロスレス型キャストは数値以外の値に対して例外をスローします。

typed() 関数は、特定の型 (クラスまたはインターフェイス) のすべてのサービスの配列を作成します。自動配線をオフにしたサービスは除外されます。複数の型をカンマ区切りで指定することができます。

services:
	- BarsDependent( typed(Bar) )

また、自動配線を使用して、特定のタイプのサービスの配列を自動的に引数として渡すこともできます。

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

services:
	- LoggersDependent( tagged(logger) )

自動配線

autowired キーにより、特定のサービスの自動配線の動作を変更することができます。詳細は自動配線の章を参照してください。

services:
	foo:
		create: Foo
		autowired: false     # fooサービスは自動配線の対象外です。

タグ

タグはサービスに補足情報を追加するために使用します。サービスには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: true を使用すると、injectアノテーションとinject*()メソッドでパブリック変数を介した依存関係の受け渡しが有効になります。

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

デフォルトでは、inject はプレゼンターに対してのみ有効です。

サービスの変更

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
version: 3.x