Nette Documentation Preview

syntax
Service Definitions
*******************

.[perex]
Configuration is the place where we instruct the DI container on how to assemble individual services and how to connect them with other dependencies. Nette provides a very clear and elegant way to achieve this.

The `services` section in the NEON configuration file is where we define our custom services and their configurations. Let's look at a simple example of defining a service named `database`, which represents an instance of the `PDO` class:

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

This configuration results in the following factory method in the [DI container|container]:

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

Service names allow us to reference them in other parts of the configuration file, using the format `@serviceName`. If there's no need to name the service, we can simply use a bullet point:

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

To retrieve a service from the DI container, we can use the `getService()` method with the service name as a parameter, or the `getByType()` method with the service type:

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


Service Creation
================

Most commonly, we create a service simply by instantiating a specific class. For example:

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

If we need to expand the configuration with additional keys, the definition can be expanded into multiple lines:

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

The `create` key has an alias `factory`, both versions are common in practice. However, we recommend using `create`.

Constructor arguments or the creation method can alternatively be written in the `arguments` key:

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

Services don't have to be created just by simple instantiation of a class; they can also result from calling static methods or methods of other services:

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

Note that for simplicity, instead of `->`, we use `::`, see [#expression means]. These factory methods are generated:

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

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

The DI container needs to know the type of the created service. If we create a service using a method that doesn't have a specified return type, we must explicitly mention this type in the configuration:

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


Arguments
=========

We pass arguments to constructors and methods in a manner very similar to regular PHP:

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

For better readability, we can list the arguments on separate lines. In this format, the use of commas is optional:

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

You can also name the arguments, which then allows you to not worry about their order:

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

If you wish to omit certain arguments and use their default values or insert a service via [autowiring], use an underscore:

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

Arguments can be services, parameters, and much more, see [#expression means].


Setup
=====

In the `setup` section, we define the methods that should be called when creating the service.

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

In PHP, this would look like:

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

In addition to method calls, you can also pass values to properties. Adding an element to an array is also supported, but you need to enclose it in quotes to avoid colliding with the NEON syntax:

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

In PHP, this would translate to:

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

In the setup, you can also call static methods or methods of other services. If you need to pass the current service as an argument, use `@self`:

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

Note that for simplicity, instead of `->`, we use `::`, see [#expression means]. This generates the following factory method:

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


Expression Means
================

Nette DI provides us with exceptionally rich expression capabilities, allowing us to articulate almost anything. In configuration files, we can use [parameters|configuration#parameters]:

```neon
# parameter
%wwwDir%

# value under a parameter key
%mailer.user%

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

We can also create objects, call methods, and functions:

```neon
# create an object
DateTime()

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

# call a PHP function
::getenv(DB_USER)
```

Refer to services either by their name or by type:

```neon
# service by name
@database

# service by type
@Nette\Database\Connection
```

Use first-class callable syntax: .{data-version:3.2.0}

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

Use constants:

```neon
# 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 `::`:

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

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

These expressions can be used anywhere when [creating services|#Service Creation], in [arguments|#Arguments], in the [#setup] section, or [parameters|configuration#parameters]:

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

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


Special Functions
-----------------

Within configuration files, you can utilize these special functions:

- `not()` for value negation
- `bool()`, `int()`, `float()`, `string()` for lossless type casting
- `typed()` to generate an array of all services of a specified type
- `tagged()` to create an array of all services with a given tag

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

Compared to conventional typecasting in PHP, like `(int)`, lossless type casting will throw an exception for non-numeric values.

The `typed()` function creates an array of all services of a particular type (class or interface). It excludes services with autowiring turned off. Multiple types can be specified, separated by commas.

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

You can also automatically pass an array of services of a specific type as an argument using [autowiring|autowiring#Collection of Services].

The `tagged()` function creates an array of all services with a specified tag. Multiple tags can be listed, separated by commas.

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


Autowiring
==========

The `autowired` key allows you to modify the autowiring behavior for a particular service. For more details, see [the autowiring chapter|autowiring].

```neon
services:
	foo:
		create: Foo
		autowired: false     # the foo service is excluded from autowiring
```


Tags
====

Tags are used to add supplementary information to services. You can assign one or more tags to a service:

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

Tags can also carry values:

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

To retrieve all services with specific tags, you can use the `tagged()` function:

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

In the DI container, you can obtain the names of all services with a specific tag using the `findByTag()` method:

```php
$names = $container->findByTag('logger');
// $names is an array containing the service name and tag value
// e.g. ['foo' => 'monolog.logger.event', ...]
```


Inject Mode
===========

Using the flag `inject: true` activates the passing of dependencies via public variables with the [inject |best-practices:inject-method-attribute#Inject Attributes] annotation and [inject*() |best-practices:inject-method-attribute#inject Methods] methods.

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

By default, `inject` is only activated for presenters.


Service Modifications
=====================

The DI container contains many services added either by built-in or [user extensions|#extensions]. You can modify the definitions of these services directly in the configuration. For instance, you can change the class of the `application.application` service, which is conventionally `Nette\Application\Application`, to something else:

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

The `alteration` flag is informative, indicating that we're merely modifying an existing service.

We can also supplement the setup:

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

When overwriting a service, you might want to remove original arguments, setup items, or tags, which is where `reset` comes in handy:

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

If you wish to remove a service added by an extension, you can do so like this:

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

Service Definitions

Configuration is the place where we instruct the DI container on how to assemble individual services and how to connect them with other dependencies. Nette provides a very clear and elegant way to achieve this.

The services section in the NEON configuration file is where we define our custom services and their configurations. Let's look at a simple example of defining a service named database, which represents an instance of the PDO class:

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

This configuration results in the following factory method in the DI container:

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

Service names allow us to reference them in other parts of the configuration file, using the format @serviceName. If there's no need to name the service, we can simply use a bullet point:

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

To retrieve a service from the DI container, we can use the getService() method with the service name as a parameter, or the getByType() method with the service type:

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

Service Creation

Most commonly, we create a service simply by instantiating a specific class. For example:

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

If we need to expand the configuration with additional keys, the definition can be expanded into multiple lines:

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

The create key has an alias factory, both versions are common in practice. However, we recommend using create.

Constructor arguments or the creation method can alternatively be written in the arguments key:

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

Services don't have to be created just by simple instantiation of a class; they can also result from calling static methods or methods of other services:

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

Note that for simplicity, instead of ->, we use ::, see expression means. These factory methods are generated:

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

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

The DI container needs to know the type of the created service. If we create a service using a method that doesn't have a specified return type, we must explicitly mention this type in the configuration:

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

Arguments

We pass arguments to constructors and methods in a manner very similar to regular PHP:

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

For better readability, we can list the arguments on separate lines. In this format, the use of commas is optional:

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

You can also name the arguments, which then allows you to not worry about their order:

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

If you wish to omit certain arguments and use their default values or insert a service via autowiring, use an underscore:

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

Arguments can be services, parameters, and much more, see expression means.

Setup

In the setup section, we define the methods that should be called when creating the service.

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

In PHP, this would look like:

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

In addition to method calls, you can also pass values to properties. Adding an element to an array is also supported, but you need to enclose it in quotes to avoid colliding with the NEON syntax:

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

In PHP, this would translate to:

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

In the setup, you can also call static methods or methods of other services. If you need to pass the current service as an argument, use @self:

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

Note that for simplicity, instead of ->, we use ::, see expression means. This generates the following factory method:

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

Expression Means

Nette DI provides us with exceptionally rich expression capabilities, allowing us to articulate almost anything. In configuration files, we can use parameters:

# parameter
%wwwDir%

# value under a parameter key
%mailer.user%

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

We can also create objects, call methods, and functions:

# create an object
DateTime()

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

# call a PHP function
::getenv(DB_USER)

Refer to services either by their name or by type:

# service by name
@database

# service by type
@Nette\Database\Connection

Use first-class callable syntax:

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

Use constants:

# 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()

These expressions can be used anywhere when creating services, in arguments, in the setup section, or parameters:

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

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

Special Functions

Within configuration files, you can utilize these special functions:

  • not() for value negation
  • bool(), int(), float(), string() for lossless type casting
  • typed() to generate an array of all services of a specified type
  • tagged() to create an array of all services with a given tag
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

Compared to conventional typecasting in PHP, like (int), lossless type casting will throw an exception for non-numeric values.

The typed() function creates an array of all services of a particular type (class or interface). It excludes services with autowiring turned off. Multiple types can be specified, separated by commas.

services:
	- BarsDependent( typed(Bar) )

You can also automatically pass an array of services of a specific type as an argument using autowiring.

The tagged() function creates an array of all services with a specified tag. Multiple tags can be listed, separated by commas.

services:
	- LoggersDependent( tagged(logger) )

Autowiring

The autowired key allows you to modify the autowiring behavior for a particular service. For more details, see the autowiring chapter.

services:
	foo:
		create: Foo
		autowired: false     # the foo service is excluded from autowiring

Tags

Tags are used to add supplementary information to services. You can assign one or more tags to a service:

services:
	foo:
		create: Foo
		tags:
			- cached

Tags can also carry values:

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

To retrieve all services with specific tags, you can use the tagged() function:

services:
	- LoggersDependent( tagged(logger) )

In the DI container, you can obtain the names of all services with a specific tag using the findByTag() method:

$names = $container->findByTag('logger');
// $names is an array containing the service name and tag value
// e.g. ['foo' => 'monolog.logger.event', ...]

Inject Mode

Using the flag inject: true activates the passing of dependencies via public variables with the inject annotation and inject*() methods.

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

By default, inject is only activated for presenters.

Service Modifications

The DI container contains many services added either by built-in or user extensions. You can modify the definitions of these services directly in the configuration. For instance, you can change the class of the application.application service, which is conventionally Nette\Application\Application, to something else:

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

The alteration flag is informative, indicating that we're merely modifying an existing service.

We can also supplement the setup:

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

When overwriting a service, you might want to remove original arguments, setup items, or tags, which is where reset comes in handy:

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

If you wish to remove a service added by an extension, you can do so like this:

services:
	cache.journal: false