Nette Documentation Preview

syntax
Fábricas generadas
******************

.[perex]
Nette DI puede generar automáticamente código de fábrica basado en interfaces, lo que le ahorra escribir código.

Una fábrica es una clase que produce y configura objetos. Por lo tanto, también les pasa sus dependencias. Por favor, no lo confunda con el patrón de diseño *factory method*, que describe una forma específica de usar fábricas y no está relacionado con este tema.

Mostramos cómo se ve una fábrica así en el [capítulo introductorio |introduction#Fábrica]:

```php
class ArticleFactory
{
	public function __construct(
		private Nette\Database\Connection $db,
	) {
	}

	public function create(): Article
	{
		return new Article($this->db);
	}
}
```

Nette DI puede generar automáticamente el código de las fábricas. Todo lo que tiene que hacer es crear una interfaz y Nette DI generará la implementación. La interfaz debe tener exactamente un método llamado `create` y declarar un tipo de retorno:

```php
interface ArticleFactory
{
	function create(): Article;
}
```

Es decir, la fábrica `ArticleFactory` tiene un método `create` que crea objetos `Article`. La clase `Article` podría verse así:

```php
class Article
{
	public function __construct(
		private Nette\Database\Connection $db,
	) {
	}
}
```

Agregamos la fábrica al archivo de configuración:

```neon
services:
	- ArticleFactory
```

Nette DI generará la implementación correspondiente de la fábrica.

En el código que usa la fábrica, solicitamos el objeto según la interfaz y Nette DI usará la implementación generada:

```php
class UserController
{
	public function __construct(
		private ArticleFactory $articleFactory,
	) {
	}

	public function foo()
	{
		// dejamos que la fábrica cree el objeto
		$article = $this->articleFactory->create();
	}
}
```


Fábrica parametrizada
=====================

El método de fábrica `create` puede aceptar parámetros, que luego pasa al constructor. Agreguemos, por ejemplo, a la clase `Article` el ID del autor del artículo:

```php
class Article
{
	public function __construct(
		private Nette\Database\Connection $db,
		private int $authorId,
	) {
	}
}
```

También agregamos el parámetro a la fábrica:

```php
interface ArticleFactory
{
	function create(int $authorId): Article;
}
```

Gracias a que el parámetro en el constructor y el parámetro en la fábrica tienen el mismo nombre, Nette DI los pasa de forma completamente automática.


Definición avanzada
===================

La definición también se puede escribir en forma multilínea usando la clave `implement`:

```neon
services:
	articleFactory:
		implement: ArticleFactory
```

Al escribir de esta manera más larga, es posible especificar argumentos adicionales para el constructor en la clave `arguments` y configuración adicional usando `setup`, al igual que con los servicios normales.

Ejemplo: si el método `create()` no aceptara el parámetro `$authorId`, podríamos especificar un valor fijo en la configuración, que se pasaría al constructor de `Article`:

```neon
services:
	articleFactory:
		implement: ArticleFactory
		arguments:
			authorId: 123
```

O viceversa, si `create()` aceptara el parámetro `$authorId`, pero no fuera parte del constructor y se pasara mediante el método `Article::setAuthorId()`, nos referiríamos a él en la sección `setup`:

```neon
services:
	articleFactory:
		implement: ArticleFactory
		setup:
			- setAuthorId($authorId)
```


Accessor
========

Además de las fábricas, Nette también puede generar los llamados accessors. Son objetos con un método `get()` que devuelve un servicio específico del contenedor DI. Las llamadas repetidas a `get()` devuelven siempre la misma instancia.

Los accessors proporcionan carga diferida (lazy-loading) a las dependencias. Supongamos que tenemos una clase que escribe errores en una base de datos especial. Si esta clase recibiera la conexión a la base de datos como dependencia a través del constructor, la conexión siempre tendría que crearse, aunque en la práctica un error ocurre solo excepcionalmente y, por lo tanto, la conexión permanecería mayormente sin usar. En lugar de eso, la clase recibe un accessor y solo cuando se llama a su `get()`, se crea el objeto de la base de datos:

¿Cómo crear un accessor? Simplemente escriba una interfaz y Nette DI generará la implementación. La interfaz debe tener exactamente un método llamado `get` y declarar un tipo de retorno:

```php
interface PDOAccessor
{
	function get(): PDO;
}
```

Agregamos el accessor al archivo de configuración, donde también está la definición del servicio que devolverá:

```neon
services:
	- PDOAccessor
	- PDO(%dsn%, %user%, %password%)
```

Dado que el accessor devuelve un servicio de tipo `PDO` y en la configuración hay un único servicio de este tipo, devolverá precisamente ese. Si hubiera más servicios del tipo dado, especificaríamos el servicio devuelto usando el nombre, por ejemplo, `- PDOAccessor(@db1)`.


Fábrica/Accessor múltiple
=========================
Hasta ahora, nuestras fábricas y accessors siempre podían producir o devolver solo un objeto. Pero también es muy fácil crear fábricas múltiples combinadas con accessors. La interfaz de tal clase contendrá cualquier número de métodos con los nombres `create<name>()` y `get<name>()`, por ejemplo:

```php
interface MultiFactory
{
	function createArticle(): Article;
	function getDb(): PDO;
}
```

Así que en lugar de pasar varias fábricas y accessors generados, pasamos una fábrica más compleja que puede hacer más cosas.

Alternativamente, en lugar de varios métodos, se puede usar `get()` con un parámetro:

```php
interface MultiFactoryAlt
{
	function get($name): PDO;
}
```

Entonces se cumple que `MultiFactory::getArticle()` hace lo mismo que `MultiFactoryAlt::get('article')`. Sin embargo, la notación alternativa tiene la desventaja de que no está claro qué valores de `$name` son compatibles y, lógicamente, tampoco es posible distinguir diferentes valores de retorno para diferentes `$name` en la interfaz.


Definición por lista
--------------------
De esta manera se puede definir una fábrica múltiple en la configuración: .{data-version:3.2.0}

```neon
services:
	- MultiFactory(
		article: Article                      # define createArticle()
		db: PDO(%dsn%, %user%, %password%)    # define getDb()
	)
```

O podemos referirnos a servicios existentes en la definición de la fábrica usando una referencia:

```neon
services:
	article: Article
	- PDO(%dsn%, %user%, %password%)
	- MultiFactory(
		article: @article    # define createArticle()
		db: @\PDO            # define getDb()
	)
```


Definición mediante tags
------------------------

La segunda opción es usar [tags |services#Tags] para la definición:

```neon
services:
	- App\Core\RouterFactory::createRouter
	- App\Model\DatabaseAccessor(
		db1: @database.db1.explorer
	)
```

Fábricas generadas

Nette DI puede generar automáticamente código de fábrica basado en interfaces, lo que le ahorra escribir código.

Una fábrica es una clase que produce y configura objetos. Por lo tanto, también les pasa sus dependencias. Por favor, no lo confunda con el patrón de diseño factory method, que describe una forma específica de usar fábricas y no está relacionado con este tema.

Mostramos cómo se ve una fábrica así en el capítulo introductorio:

class ArticleFactory
{
	public function __construct(
		private Nette\Database\Connection $db,
	) {
	}

	public function create(): Article
	{
		return new Article($this->db);
	}
}

Nette DI puede generar automáticamente el código de las fábricas. Todo lo que tiene que hacer es crear una interfaz y Nette DI generará la implementación. La interfaz debe tener exactamente un método llamado create y declarar un tipo de retorno:

interface ArticleFactory
{
	function create(): Article;
}

Es decir, la fábrica ArticleFactory tiene un método create que crea objetos Article. La clase Article podría verse así:

class Article
{
	public function __construct(
		private Nette\Database\Connection $db,
	) {
	}
}

Agregamos la fábrica al archivo de configuración:

services:
	- ArticleFactory

Nette DI generará la implementación correspondiente de la fábrica.

En el código que usa la fábrica, solicitamos el objeto según la interfaz y Nette DI usará la implementación generada:

class UserController
{
	public function __construct(
		private ArticleFactory $articleFactory,
	) {
	}

	public function foo()
	{
		// dejamos que la fábrica cree el objeto
		$article = $this->articleFactory->create();
	}
}

Fábrica parametrizada

El método de fábrica create puede aceptar parámetros, que luego pasa al constructor. Agreguemos, por ejemplo, a la clase Article el ID del autor del artículo:

class Article
{
	public function __construct(
		private Nette\Database\Connection $db,
		private int $authorId,
	) {
	}
}

También agregamos el parámetro a la fábrica:

interface ArticleFactory
{
	function create(int $authorId): Article;
}

Gracias a que el parámetro en el constructor y el parámetro en la fábrica tienen el mismo nombre, Nette DI los pasa de forma completamente automática.

Definición avanzada

La definición también se puede escribir en forma multilínea usando la clave implement:

services:
	articleFactory:
		implement: ArticleFactory

Al escribir de esta manera más larga, es posible especificar argumentos adicionales para el constructor en la clave arguments y configuración adicional usando setup, al igual que con los servicios normales.

Ejemplo: si el método create() no aceptara el parámetro $authorId, podríamos especificar un valor fijo en la configuración, que se pasaría al constructor de Article:

services:
	articleFactory:
		implement: ArticleFactory
		arguments:
			authorId: 123

O viceversa, si create() aceptara el parámetro $authorId, pero no fuera parte del constructor y se pasara mediante el método Article::setAuthorId(), nos referiríamos a él en la sección setup:

services:
	articleFactory:
		implement: ArticleFactory
		setup:
			- setAuthorId($authorId)

Accessor

Además de las fábricas, Nette también puede generar los llamados accessors. Son objetos con un método get() que devuelve un servicio específico del contenedor DI. Las llamadas repetidas a get() devuelven siempre la misma instancia.

Los accessors proporcionan carga diferida (lazy-loading) a las dependencias. Supongamos que tenemos una clase que escribe errores en una base de datos especial. Si esta clase recibiera la conexión a la base de datos como dependencia a través del constructor, la conexión siempre tendría que crearse, aunque en la práctica un error ocurre solo excepcionalmente y, por lo tanto, la conexión permanecería mayormente sin usar. En lugar de eso, la clase recibe un accessor y solo cuando se llama a su get(), se crea el objeto de la base de datos:

¿Cómo crear un accessor? Simplemente escriba una interfaz y Nette DI generará la implementación. La interfaz debe tener exactamente un método llamado get y declarar un tipo de retorno:

interface PDOAccessor
{
	function get(): PDO;
}

Agregamos el accessor al archivo de configuración, donde también está la definición del servicio que devolverá:

services:
	- PDOAccessor
	- PDO(%dsn%, %user%, %password%)

Dado que el accessor devuelve un servicio de tipo PDO y en la configuración hay un único servicio de este tipo, devolverá precisamente ese. Si hubiera más servicios del tipo dado, especificaríamos el servicio devuelto usando el nombre, por ejemplo, - PDOAccessor(@db1).

Fábrica/Accessor múltiple

Hasta ahora, nuestras fábricas y accessors siempre podían producir o devolver solo un objeto. Pero también es muy fácil crear fábricas múltiples combinadas con accessors. La interfaz de tal clase contendrá cualquier número de métodos con los nombres create<name>() y get<name>(), por ejemplo:

interface MultiFactory
{
	function createArticle(): Article;
	function getDb(): PDO;
}

Así que en lugar de pasar varias fábricas y accessors generados, pasamos una fábrica más compleja que puede hacer más cosas.

Alternativamente, en lugar de varios métodos, se puede usar get() con un parámetro:

interface MultiFactoryAlt
{
	function get($name): PDO;
}

Entonces se cumple que MultiFactory::getArticle() hace lo mismo que MultiFactoryAlt::get('article'). Sin embargo, la notación alternativa tiene la desventaja de que no está claro qué valores de $name son compatibles y, lógicamente, tampoco es posible distinguir diferentes valores de retorno para diferentes $name en la interfaz.

Definición por lista

De esta manera se puede definir una fábrica múltiple en la configuración:

services:
	- MultiFactory(
		article: Article                      # define createArticle()
		db: PDO(%dsn%, %user%, %password%)    # define getDb()
	)

O podemos referirnos a servicios existentes en la definición de la fábrica usando una referencia:

services:
	article: Article
	- PDO(%dsn%, %user%, %password%)
	- MultiFactory(
		article: @article    # define createArticle()
		db: @\PDO            # define getDb()
	)

Definición mediante tags

La segunda opción es usar tags para la definición:

services:
	- App\Core\RouterFactory::createRouter
	- App\Model\DatabaseAccessor(
		db1: @database.db1.explorer
	)