Configuración del contenedor DI

Resumen de las opciones de configuración del contenedor DI de Nette.

Archivo de configuración

El contenedor DI de Nette se controla fácilmente con archivos de configuración. Normalmente se escriben en el formato NEON. Para editarlos recomendamos editores con soporte para este formato.

 decorator: 	Decorator
di: Contenedor DI
extensions: Instalación de extensiones DI adicionales
includes: Inclusión de archivos
parameters: Parámetros
search: Registro automático de servicios
services: Servicios

Para escribir una cadena que contenga el carácter %, hay que escaparlo duplicándolo a %%.

Parámetros

En la configuración puede definir parámetros que después se pueden usar como parte de las definiciones de los servicios. Eso le permite aclarar la configuración o centralizar valores que pueden cambiar.

parameters:
	dsn: 'mysql:host=127.0.0.1;dbname=test'
	user: root
	password: secret

Al parámetro dsn nos referimos en cualquier lugar de la configuración con la notación %dsn%. Los parámetros se pueden usar también dentro de cadenas como '%wwwDir%/images'.

Los parámetros no tienen por qué ser solo cadenas o números: también pueden contener arrays:

parameters:
	mailer:
		host: smtp.example.com
		secure: ssl
		user: franta@gmail.com
	languages: [cs, en, de]

A una clave concreta nos referimos como %mailer.user%.

Si su código (p. ej. una clase) necesita el valor de un parámetro, páseselo a la clase. Por ejemplo, en el constructor. No existe ningún objeto de configuración global al que las clases puedan preguntar por los valores de los parámetros. Eso sería una violación del principio de la inyección de dependencias.

Servicios

Véase el capítulo aparte.

Decorator

¿Cómo modificar de una vez varios servicios de un determinado tipo? Por ejemplo, ¿cómo llamar a un método concreto en todos los presenters que heredan de una determinada clase base? Para eso está el decorator.

decorator:
	# para todos los servicios que sean instancias de esta clase o interfaz
	App\Presentation\BasePresenter:
		setup:
			- setProjectId(10)       # llama a este método
			- $absoluteUrls = true   # y establece la variable

El decorator se puede usar también para poner etiquetas o para activar el modo inject.

decorator:
	InjectableInterface:
		tags: [mytag: 1]
		inject: true

DI

Ajustes técnicos del contenedor DI.

di:
	# ¿mostrar el DIC en la Tracy Bar?
	debugger: ...        # (bool) de forma predeterminada se autodetecta (activado si Tracy está presente)

	# tipos de parámetros que nunca se autoconectan
	excluded: ...        # (string[])

	# ¿activar la creación lazy de los servicios?
	lazy: ...            # (bool) el valor predeterminado es false

	# la clase de la que hereda el contenedor DI
	parentClass: ...     # (string) el valor predeterminado es Nette\DI\Container

Servicios lazy

El ajuste lazy: true activa la creación lazy (diferida) de los servicios. Eso significa que los servicios no se crean realmente en el momento en que se piden al contenedor DI, sino solo en el momento de su primer uso. Esto puede acelerar el arranque de la aplicación y reducir el consumo de memoria, porque solo se crean los servicios realmente necesarios para cada petición.

Para un servicio concreto, la creación lazy se puede ajustar.

Los objetos lazy solo se pueden usar para clases definidas por el usuario, no para clases internas de PHP. Requiere PHP 8.4 o superior.

Exportación de metadatos

La clase del contenedor DI contiene también muchos metadatos. Puede reducir su tamaño reduciendo la exportación de metadatos.

di:
	export:
		# ¿exportar los parámetros?
		parameters: false   # (bool) el valor predeterminado es true

		# ¿exportar las etiquetas y cuáles?
		tags:               # (string[]|bool) de forma predeterminada, todas
			- event.subscriber

		# ¿exportar los datos para el autowiring y cuáles?
		types:              # (string[]|bool) de forma predeterminada, todos
			- Nette\Database\Connection
			- Symfony\Component\Console\Application

Si no usa $container->getParameters(), puede desactivar la exportación de parámetros. Además, puede exportar solo las etiquetas que realmente usa para obtener servicios con $container->findByTag(...). Si no llama a ese método en absoluto, puede desactivar por completo la exportación de etiquetas con false.

Puede reducir considerablemente los metadatos para el autowiring enumerando solo las clases que realmente pide con $container->getByType(). De nuevo, si no llama a ese método (o lo llama solo en el archivo de bootstrap, p. ej. para obtener Nette\Application\Application), puede desactivar por completo la exportación de tipos con false.

Extensiones

Registro de extensiones DI adicionales. Así se añade, por ejemplo, la extensión DI Dibi\Bridges\Nette\DibiExtension3 bajo el nombre dibi:

extensions:
	dibi: Dibi\Bridges\Nette\DibiExtension3

Después la configura en la sección dibi:

dibi:
	host: localhost

También puede añadir como extensión una clase con parámetros:

extensions:
	application: Nette\Bridges\ApplicationDI\ApplicationExtension(%debugMode%, [%appDir%], %tempDir%/cache)

Inclusión de archivos

Se pueden incluir archivos de configuración adicionales en la sección includes:

includes:
	- parameters.php
	- services.neon
	- presenters.neon

El nombre parameters.php no es una errata; la configuración también se puede escribir en un archivo PHP que la devuelva como array:

<?php
return [
	'database' => [
		'main' => [
			'dsn' => 'sqlite::memory:',
		],
	],
];

Si en varios archivos de configuración aparecen elementos con las mismas claves, se sobrescriben o, en el caso de los arrays, se fusionan. Un archivo incluido después tiene mayor prioridad que el anterior. El archivo en el que está la sección includes tiene mayor prioridad que los archivos incluidos en él.

El registro automático de servicios en el contenedor DI simplifica notablemente el desarrollo. Nette añade los presenters al contenedor automáticamente, pero puede añadir con facilidad cualquier otra clase.

Basta con indicar en qué directorios (y subdirectorios) deben buscarse las clases:

search:
	-	in: %appDir%/Forms
	-	in: %appDir%/Model

Si solo necesita una única regla de búsqueda, puede omitir la lista y escribir sus claves directamente bajo search:

search:
	in: %appDir%

Normalmente, sin embargo, no queremos añadir absolutamente todas las clases e interfaces, así que podemos filtrarlas:

search:
	-	in: %appDir%/Forms

		# filtrado por nombre de archivo (string|string[])
		files:
			- *Factory.php

		# filtrado por nombre de clase (string|string[])
		classes:
			- *Factory

O podemos elegir las clases que heredan o implementan al menos una de las clases indicadas:

search:
	-	in: %appDir%
		extends:
			- App\*Form
		implements:
			- App\*FormInterface

También puede definir reglas de exclusión mediante máscaras de nombres de clase o de antecesores. Si una clase encaja con una regla de exclusión, no se añadirá al contenedor DI:

search:
	-	in: %appDir%
		exclude:
			files: ...
			classes: ...
			extends: ...
			implements: ...

A todos los servicios registrados automáticamente se les pueden asignar etiquetas:

search:
	-	in: %appDir%
		tags: ...

Además de las clases, la búsqueda registra también las interfaces que tienen un único método create() o get(), como factories o accessors generados. Las clases para las que ya hay registrado en el contenedor un servicio del mismo tipo se omiten, así que no se crean duplicados.

Fusión

Si en varios archivos de configuración aparecen elementos con las mismas claves, se sobrescriben o, en el caso de los arrays, se fusionan. El archivo incluido después tiene mayor prioridad que el anterior.

config1.neon config2.neon resultado
items:
	- 1
	- 2
items:
	- 3
items:
	- 1
	- 2
	- 3

En el caso de los arrays se puede impedir la fusión añadiendo un signo de exclamación tras el nombre de la clave:

config1.neon config2.neon resultado
items:
	- 1
	- 2
items!:
	- 3
items:
	- 3
versión: 3.x