Nette Documentation Preview

syntax
Definições de serviço
*********************

.[perex]
A configuração é o local em que instruímos o contêiner DI sobre como montar serviços individuais e como conectá-los a outras dependências. O Nette oferece uma maneira muito clara e elegante de fazer isso.

A seção `services` no arquivo de configuração do NEON é onde definimos nossos serviços personalizados e suas configurações. Vamos dar uma olhada em um exemplo simples de definição de um serviço chamado `database`, que representa uma instância da classe `PDO`:

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

Essa configuração resulta no seguinte método de fábrica no [contêiner DI |container]:

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

Os nomes dos serviços nos permitem fazer referência a eles em outras partes do arquivo de configuração, usando o formato `@serviceName`. Se não houver necessidade de nomear o serviço, podemos simplesmente usar um marcador:

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

Para recuperar um serviço do contêiner DI, podemos usar o método `getService()` com o nome do serviço como parâmetro ou o método `getByType()` com o tipo de serviço:

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


Criação de serviços .[#toc-service-creation]
============================================

Geralmente, criamos um serviço simplesmente instanciando uma classe específica. Por exemplo:

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

Se precisarmos expandir a configuração com chaves adicionais, a definição poderá ser expandida em várias linhas:

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

A chave `create` tem um alias `factory`, ambas as versões são comuns na prática. No entanto, recomendamos o uso de `create`.

Como alternativa, os argumentos do construtor ou o método de criação podem ser escritos na chave `arguments`:

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

Os serviços não precisam ser criados apenas pela simples instanciação de uma classe; eles também podem resultar da chamada de métodos estáticos ou métodos de outros serviços:

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

Observe que, para simplificar, em vez de `->`, usamos `::`, veja a [expressão significa |#expression means]. Esses métodos de fábrica são gerados:

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

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

O contêiner DI precisa saber o tipo do serviço criado. Se criarmos um serviço usando um método que não tenha um tipo de retorno especificado, devemos mencionar explicitamente esse tipo na configuração:

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


Argumentos .[#toc-arguments]
============================

Passamos argumentos para construtores e métodos de forma muito semelhante ao PHP comum:

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

Para facilitar a leitura, podemos listar os argumentos em linhas separadas. Nesse formato, o uso de vírgulas é opcional:

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

Você também pode nomear os argumentos, o que permite que você não se preocupe com a ordem deles:

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

Se quiser omitir determinados argumentos e usar seus valores padrão ou inserir um serviço por meio da [conexão automática |autowiring], use um sublinhado:

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

Os argumentos podem ser serviços, parâmetros e muito mais; consulte os [meios de expressão |#expression means].


Configuração .[#toc-setup]
==========================

Na seção `setup`, definimos os métodos que devem ser chamados ao criar o serviço.

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

Em PHP, isso seria parecido com:

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

Além das chamadas de método, você também pode passar valores para as propriedades. A adição de um elemento a uma matriz também é suportada, mas você precisa colocá-la entre aspas para evitar colidir com a sintaxe NEON:

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

Em PHP, isso se traduziria em:

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

Na configuração, você também pode chamar métodos estáticos ou métodos de outros serviços. Se você precisar passar o serviço atual como um argumento, use `@self`:

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

Observe que, para simplificar, em vez de `->`, usamos `::`, veja a [expressão significa |#expression means]. Isso gera o seguinte método de fábrica:

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


Meios de Expressão .[#toc-expression-means]
===========================================

O Nette DI nos fornece recursos de expressão excepcionalmente ricos, o que nos permite articular quase tudo. Nos arquivos de configuração, podemos usar [parâmetros |configuration#parameters]:

```neon
# parâmetro
%wwwDir%

# valor em uma chave de parâmetro
%mailer.user%

# parâmetro em uma cadeia de caracteres
'%wwwDir%/images'
```

Também podemos criar objetos, chamar métodos e funções:

```neon
# criar um objeto
DateTime()

# chamar um método estático
Collator::create(%locale%)

# chamar uma função PHP
::getenv(DB_USER)
```

Referir-se aos serviços pelo nome ou pelo tipo:

```neon
# serviço por nome
@database

# serviço por tipo
@Nette\Database\Connection
```

Use a sintaxe chamável de primeira classe: .{data-version:3.2.0}

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

Usar constantes:

```neon
# constante de classe
FilesystemIterator::SKIP_DOTS

# constante global obtida pela função constant() do PHP
::constant(PHP_VERSION)
```

As chamadas de método podem ser encadeadas, assim como no PHP. Para simplificar, em vez de `->`, usamos `::`:

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

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

Essas expressões podem ser usadas em qualquer lugar ao [criar serviços |#Service Creation], em [argumentos |#Arguments], na seção de [configuração |#setup] ou em [parâmetros |configuration#parameters]:

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

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


Funções especiais .[#toc-special-functions]
-------------------------------------------

Nos arquivos de configuração, você pode utilizar essas funções especiais:

- `not()` para negação de valor
- `bool()`, `int()`, `float()`, `string()` para conversão de tipos sem perdas
- `typed()` para gerar uma matriz de todos os serviços de um tipo especificado
- `tagged()` para criar uma matriz de todos os serviços com uma determinada tag

```neon
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)
```

Em comparação com o typecasting convencional em PHP, como `(int)`, o lossless type casting lançará uma exceção para valores não numéricos.

A função `typed()` cria uma matriz de todos os serviços de um tipo específico (classe ou interface). Ela exclui os serviços com o autowiring desativado. Vários tipos podem ser especificados, separados por vírgulas.

```neon
services:
	- BarsDependent( typed(Bar) )
```

Você também pode passar automaticamente uma matriz de serviços de um tipo específico como um argumento usando o [autowiring |autowiring#Collection of Services].

A função `tagged()` cria uma matriz de todos os serviços com uma tag especificada. Várias tags podem ser listadas, separadas por vírgulas.

```neon
services:
	- LoggersDependent( tagged(logger) )
```


Fiação automática .[#toc-autowiring]
====================================

A chave `autowired` permite modificar o comportamento de conexão automática de um serviço específico. Para obter mais detalhes, consulte [o capítulo Aut |autowiring]owiring.

```neon
services:
	foo:
		create: Foo
		autowired: false     # O serviço foo está excluído da autocablagem
```


Tags .[#toc-tags]
=================

As tags são usadas para adicionar informações suplementares aos serviços. Você pode atribuir uma ou mais tags a um serviço:

```neon
services:
	foo:
		create: Foo
		tags:
			- cached
```

As tags também podem conter valores:

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

Para recuperar todos os serviços com tags específicas, você pode usar a função `tagged()`:

```neon
services:
	- LoggersDependent( tagged(logger) )
```

No contêiner DI, você pode obter os nomes de todos os serviços com uma tag específica usando o método `findByTag()`:

```php
$names = $container->findByTag('logger');
// $names é uma matriz que contém o nome do serviço e o valor da tag
// Por exemplo, ['foo' => 'monolog.logger.event', ...]
```


Modo de injeção .[#toc-inject-mode]
===================================

O uso do sinalizador `inject: true` ativa a passagem de dependências por meio de variáveis públicas com a anotação [inject |best-practices:inject-method-attribute#Inject Attributes] e os métodos [inject*() |best-practices:inject-method-attribute#inject Methods].

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

Por padrão, o `inject` só é ativado para apresentadores.


Modificações no serviço .[#toc-service-modifications]
=====================================================

O contêiner DI contém muitos serviços adicionados por [extensões |#extensions] internas ou [de usuário |#extensions]. Você pode modificar as definições desses serviços diretamente na configuração. Por exemplo, você pode alterar a classe do serviço `application.application`, que é convencionalmente `Nette\Application\Application`, para outra:

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

O sinalizador `alteration` é informativo, indicando que estamos apenas modificando um serviço existente.

Também podemos complementar a configuração:

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

Ao substituir um serviço, talvez você queira remover argumentos, itens de configuração ou tags originais, e é aí que o `reset` se torna útil:

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

Se quiser remover um serviço adicionado por uma extensão, você pode fazer isso da seguinte forma:

```neon
services:
	cache.journal: false
```

Definições de serviço

A configuração é o local em que instruímos o contêiner DI sobre como montar serviços individuais e como conectá-los a outras dependências. O Nette oferece uma maneira muito clara e elegante de fazer isso.

A seção services no arquivo de configuração do NEON é onde definimos nossos serviços personalizados e suas configurações. Vamos dar uma olhada em um exemplo simples de definição de um serviço chamado database, que representa uma instância da classe PDO:

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

Essa configuração resulta no seguinte método de fábrica no contêiner DI:

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

Os nomes dos serviços nos permitem fazer referência a eles em outras partes do arquivo de configuração, usando o formato @serviceName. Se não houver necessidade de nomear o serviço, podemos simplesmente usar um marcador:

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

Para recuperar um serviço do contêiner DI, podemos usar o método getService() com o nome do serviço como parâmetro ou o método getByType() com o tipo de serviço:

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

Criação de serviços

Geralmente, criamos um serviço simplesmente instanciando uma classe específica. Por exemplo:

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

Se precisarmos expandir a configuração com chaves adicionais, a definição poderá ser expandida em várias linhas:

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

A chave create tem um alias factory, ambas as versões são comuns na prática. No entanto, recomendamos o uso de create.

Como alternativa, os argumentos do construtor ou o método de criação podem ser escritos na chave arguments:

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

Os serviços não precisam ser criados apenas pela simples instanciação de uma classe; eles também podem resultar da chamada de métodos estáticos ou métodos de outros serviços:

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

Observe que, para simplificar, em vez de ->, usamos ::, veja a expressão significa. Esses métodos de fábrica são gerados:

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

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

O contêiner DI precisa saber o tipo do serviço criado. Se criarmos um serviço usando um método que não tenha um tipo de retorno especificado, devemos mencionar explicitamente esse tipo na configuração:

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

Argumentos

Passamos argumentos para construtores e métodos de forma muito semelhante ao PHP comum:

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

Para facilitar a leitura, podemos listar os argumentos em linhas separadas. Nesse formato, o uso de vírgulas é opcional:

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

Você também pode nomear os argumentos, o que permite que você não se preocupe com a ordem deles:

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

Se quiser omitir determinados argumentos e usar seus valores padrão ou inserir um serviço por meio da conexão automática, use um sublinhado:

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

Os argumentos podem ser serviços, parâmetros e muito mais; consulte os meios de expressão.

Configuração

Na seção setup, definimos os métodos que devem ser chamados ao criar o serviço.

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

Em PHP, isso seria parecido com:

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

Além das chamadas de método, você também pode passar valores para as propriedades. A adição de um elemento a uma matriz também é suportada, mas você precisa colocá-la entre aspas para evitar colidir com a sintaxe NEON:

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

Em PHP, isso se traduziria em:

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

Na configuração, você também pode chamar métodos estáticos ou métodos de outros serviços. Se você precisar passar o serviço atual como um argumento, use @self:

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

Observe que, para simplificar, em vez de ->, usamos ::, veja a expressão significa. Isso gera o seguinte método de fábrica:

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

Meios de Expressão

O Nette DI nos fornece recursos de expressão excepcionalmente ricos, o que nos permite articular quase tudo. Nos arquivos de configuração, podemos usar parâmetros:

# parâmetro
%wwwDir%

# valor em uma chave de parâmetro
%mailer.user%

# parâmetro em uma cadeia de caracteres
'%wwwDir%/images'

Também podemos criar objetos, chamar métodos e funções:

# criar um objeto
DateTime()

# chamar um método estático
Collator::create(%locale%)

# chamar uma função PHP
::getenv(DB_USER)

Referir-se aos serviços pelo nome ou pelo tipo:

# serviço por nome
@database

# serviço por tipo
@Nette\Database\Connection

Use a sintaxe chamável de primeira classe:

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

Usar constantes:

# constante de classe
FilesystemIterator::SKIP_DOTS

# constante global obtida pela função constant() do PHP
::constant(PHP_VERSION)

As chamadas de método podem ser encadeadas, assim como no PHP. Para simplificar, em vez de ->, usamos :::

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

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

Essas expressões podem ser usadas em qualquer lugar ao criar serviços, em argumentos, na seção de configuração ou em parâmetros:

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

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

Funções especiais

Nos arquivos de configuração, você pode utilizar essas funções especiais:

  • not() para negação de valor
  • bool(), int(), float(), string() para conversão de tipos sem perdas
  • typed() para gerar uma matriz de todos os serviços de um tipo especificado
  • tagged() para criar uma matriz de todos os serviços com uma determinada tag
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

Em comparação com o typecasting convencional em PHP, como (int), o lossless type casting lançará uma exceção para valores não numéricos.

A função typed() cria uma matriz de todos os serviços de um tipo específico (classe ou interface). Ela exclui os serviços com o autowiring desativado. Vários tipos podem ser especificados, separados por vírgulas.

services:
	- BarsDependent( typed(Bar) )

Você também pode passar automaticamente uma matriz de serviços de um tipo específico como um argumento usando o autowiring.

A função tagged() cria uma matriz de todos os serviços com uma tag especificada. Várias tags podem ser listadas, separadas por vírgulas.

services:
	- LoggersDependent( tagged(logger) )

Fiação automática

A chave autowired permite modificar o comportamento de conexão automática de um serviço específico. Para obter mais detalhes, consulte o capítulo Autowiring.

services:
	foo:
		create: Foo
		autowired: false     # O serviço foo está excluído da autocablagem

Tags

As tags são usadas para adicionar informações suplementares aos serviços. Você pode atribuir uma ou mais tags a um serviço:

services:
	foo:
		create: Foo
		tags:
			- cached

As tags também podem conter valores:

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

Para recuperar todos os serviços com tags específicas, você pode usar a função tagged():

services:
	- LoggersDependent( tagged(logger) )

No contêiner DI, você pode obter os nomes de todos os serviços com uma tag específica usando o método findByTag():

$names = $container->findByTag('logger');
// $names é uma matriz que contém o nome do serviço e o valor da tag
// Por exemplo, ['foo' => 'monolog.logger.event', ...]

Modo de injeção

O uso do sinalizador inject: true ativa a passagem de dependências por meio de variáveis públicas com a anotação inject e os métodos inject*().

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

Por padrão, o inject só é ativado para apresentadores.

Modificações no serviço

O contêiner DI contém muitos serviços adicionados por extensões internas ou de usuário. Você pode modificar as definições desses serviços diretamente na configuração. Por exemplo, você pode alterar a classe do serviço application.application, que é convencionalmente Nette\Application\Application, para outra:

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

O sinalizador alteration é informativo, indicando que estamos apenas modificando um serviço existente.

Também podemos complementar a configuração:

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

Ao substituir um serviço, talvez você queira remover argumentos, itens de configuração ou tags originais, e é aí que o reset se torna útil:

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

Se quiser remover um serviço adicionado por uma extensão, você pode fazer isso da seguinte forma:

services:
	cache.journal: false