Definições de serviço

A configuração é onde colocamos as definições de serviços personalizados. Isto é feito na seção services.

Por exemplo, é assim que criamos um serviço chamado database, que será uma instância da classe PDO:

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

A nomenclatura dos serviços é utilizada para nos permitir referenciá-los. Se um serviço não é referenciado, não há necessidade de nomeá-lo. Portanto, usamos apenas um ponto em vez de um nome:

services:
	- PDO('sqlite::memory:') # serviço anônimo

Uma entrada de uma linha pode ser dividida em várias linhas para permitir que chaves adicionais sejam adicionadas, tais como configuração. O pseudônimo para a chave create: é factory:.

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

Recuperamos então o serviço do recipiente DI usando o método getService() pelo nome, ou melhor ainda, o método getByType() pelo tipo:

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

Criando um serviço

Na maioria das vezes, nós criamos um serviço simplesmente criando uma instância de uma classe:

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

O que gerará um método de fábrica em contêineres DI:

public function createServiceDatabase(): PDO
{
	return new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'secret');
}

Alternativamente, uma chave arguments pode ser usada para passar argumentos:

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

Um método estático também pode criar um serviço:

services:
	database: My\Database::create(root, secret)

Corresponde ao código PHP:

public function createServiceDatabase(): PDO
{
	return My\Database::create('root', 'secret');
}

Presume-se que um método estático My\Database::create() tenha um valor de retorno definido que o recipiente DI precisa conhecer. Se não o tiver, escrevemos o tipo na configuração:

services:
	database:
		create: My\Database::create(root, secret)
		type: PDO

A Nette DI lhe dá facilidades de expressão extremamente poderosas para escrever quase tudo. Por exemplo, para se referir a outro serviço e chamar seu método. Para simplificar, :: é usado ao invés de ->.

services:
	routerFactory: App\Router\Factory
	router: @routerFactory::create()

Corresponde ao código PHP:

public function createServiceRouterFactory(): App\Router\Factory
{
	return new App\Router\Factory;
}

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

As chamadas de métodos podem ser encadeadas como em PHP:

services:
	foo: FooFactory::build()::get()

Corresponde ao código PHP:

public function createServiceFoo()
{
	return FooFactory::build()->get();
}

Argumentos

Os parâmetros nomeados também podem ser usados para passar argumentos:

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

O uso de vírgulas é opcional ao quebrar argumentos em várias linhas.

Naturalmente, também podemos utilizar outros serviços ou parâmetros como argumentos:

services:
	- Foo(@anotherService, %appDir%)

Corresponde ao código PHP:

public function createService01(): Foo
{
	return new Foo($this->getService('anotherService'), '...');
}

Se o primeiro argumento for auto-cablado e você quiser especificar o segundo, omitir o primeiro com o _ character, for example Foo(_, %appDir%). Ou melhor ainda, passar apenas o segundo argumento como um parâmetro nomeado, por exemplo Foo(path: %appDir%).

Nette DI e o formato NEON lhe dão facilidades extremamente poderosas para escrever quase tudo. Assim, um argumento pode ser um objeto recém-criado, você pode chamar métodos estáticos, métodos de outros serviços, ou mesmo funções globais usando notação especial:

services:
	analisador: Meu Analisador (
		FilesystemIterator(%appDir%)        # criar objeto
		DateTime::createFromFormat('Y-m-d') # chama método estático
		@anotherService                     # passando outro serviço
		@http.request::getRemoteAddress()   # chamando outro método de serviço
		::getenv(NetteMode)                 # chamar uma função global
	)

Corresponde ao código PHP:

public function createServiceAnalyser(): My\Analyser
{
	return new My\Analyser(
		new FilesystemIterator('...'),
		DateTime::createFromFormat('Y-m-d'),
		$this->getService('anotherService'),
		$this->getService('http.request')->getRemoteAddress(),
		getenv('NetteMode')
	);
}

Funções especiais

Você também pode usar funções especiais em argumentos para lançar ou negar valores:

  • not(%arg%) negação
  • bool(%arg%) elenco sem perdas a bool
  • int(%arg%) elenco sem perdas para int
  • float(%arg%) elenco sem perdas para flutuar
  • string(%arg%) elenco sem perdas para cordas
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

A reescrita sem perdas difere da reescrita normal em PHP, por exemplo, usando (int), na medida em que lança uma exceção para valores não-numéricos.

Múltiplos serviços podem ser passados como argumentos. Um conjunto de todos os serviços de um determinado tipo (ou seja, classe ou interface) é criado pela função typed(). A função omitirá serviços que tenham a fiação automática desativada, e múltiplos tipos separados por uma vírgula podem ser especificados.

services:
	- BarsDependent( typed(Bar) )

Você também pode passar um conjunto de serviços automaticamente usando a fiação automática.

Um conjunto de todos os serviços com uma certa etiqueta é criado pela função tagged(). Múltiplas tags separadas por uma vírgula podem ser especificadas.

services:
	- LoggersDependent( tagged(logger) )

Serviços de referência

Os serviços individuais são referenciados usando o personagem @ and name, so for example @database:

services:
	- create: Foo(@database)
	  setup:
			- setCacheStorage(@cache.storage)

Corresponde ao código PHP:

public function createService01(): Foo
{
	$service = new Foo($this->getService('database'));
	$service->setCacheStorage($this->getService('cache.storage'));
	return $service;
}

Mesmo serviços anônimos podem ser referenciados usando uma chamada de retorno, basta especificar seu tipo (classe ou interface) ao invés de seu nome. No entanto, isto geralmente não é necessário devido ao cabeamento automático.

services:
	- create: Foo(@Nette\Database\Connection)  # or @\PDO
	  setup:
			- setCacheStorage(@cache.storage)

Configuração

Na seção de configuração, listamos os métodos a serem chamados ao criar o serviço:

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

Corresponde ao código PHP:

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

Também é possível definir os locais adequados. A adição de um elemento a uma matriz também é apoiada, e deve ser escrita entre aspas para não entrar em conflito com a sintaxe NEON:

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

Corresponde ao código PHP:

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

No entanto, métodos estáticos ou métodos de outros serviços também podem ser chamados na configuração. Passamos o serviço real a eles como @self:

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

Corresponde ao código PHP:

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

Cablagem automática

A chave autowired pode ser usada para excluir um serviço da autowired ou para influenciar seu comportamento. Consulte o capítulo sobre a fiação automática para obter mais informações.

services:
	foo:
		create: Foo
		autowired: false     # foo é removido do autowiring

Etiquetas

As informações do usuário podem ser adicionadas aos serviços individuais sob a forma de tags:

services:
	foo:
		create: Foo
		tags:
			- cached

As etiquetas também podem ter um valor:

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

Uma série de serviços com determinadas tags pode ser passada como argumento usando a função tagged(). Múltiplas tags separadas por uma vírgula também podem ser especificadas.

services:
	- LoggersDependent( tagged(logger) )

Os nomes dos serviços podem ser obtidos no recipiente DI usando o método findByTag():

$names = $container->findByTag('logger');
// $names é um array contendo o nome do serviço e o valor da etiqueta
// i.e. ['foo' => 'monolog.logger.event', ...]

Modo injetado

A bandeira inject: true é usada para ativar a passagem de dependências através de variáveis públicas com a anotação de injeção e os métodos de injeção*().

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

Por padrão, inject é ativado somente para apresentadores.

Modificação de serviços

Há uma série de serviços no contêiner DI que foram acrescentados por embutido ou por sua extensão. As definições desses serviços podem ser modificadas na configuração. Por exemplo, para o serviço application.application, que é por padrão um objeto Nette\Application\Application, podemos alterar a classe:

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

A bandeira alteration é informativa e diz que estamos apenas modificando um serviço existente.

Também podemos acrescentar uma configuração:

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

Ao reescrever um serviço, podemos querer remover os argumentos originais, itens de configuração ou tags, que é para isso que serve reset:

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

Um serviço adicionado por extensão também pode ser removido do container:

services:
	cache.journal: false
versão: 3.x