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çãobool(%arg%)
elenco sem perdas a boolint(%arg%)
elenco sem perdas para intfloat(%arg%)
elenco sem perdas para flutuarstring(%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