Nette Documentation Preview

syntax
Generált gyárak
***************

.[perex]
A Nette DI képes automatikusan gyárkódot generálni a felület alapján, ami megkíméli Önt a kód írásától.

A gyár egy olyan osztály, amely objektumokat hoz létre és konfigurál. Ezért a függőségeiket is átadja nekik. Kérjük, ne keverjük össze a *factory method* tervezési mintával, amely a gyárak használatának egy speciális módját írja le, és nem kapcsolódik ehhez a témához.

A [bevezető fejezetben |introduction#factory] megmutattuk, hogyan néz ki egy ilyen gyár:

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

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

A Nette DI képes automatikusan gyárkódot generálni. Csak egy interfészt kell létrehozni, és a Nette DI generál egy implementációt. Az interfésznek pontosan egy `create` nevű metódussal kell rendelkeznie, és deklarálnia kell egy visszatérési típust:

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

Tehát a `ArticleFactory` gyárnak van egy `create` metódusa, amely létrehozza a `Article` objektumokat. A `Article` osztály például a következőképpen nézhet ki:

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

Adja hozzá a gyárat a konfigurációs fájlhoz:

```neon
services:
	- ArticleFactory
```

A Nette DI létrehozza a megfelelő gyár implementációját.

Így a gyárat használó kódban az objektumot interfész szerint kérjük, és a Nette DI a generált implementációt használja:

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

	public function foo()
	{
		// hagyjuk, hogy a gyár létrehozzon egy objektumot
		$article = $this->articleFactory->create();
	}
}
```


Paraméteres gyár .[#toc-parameterized-factory]
==============================================

A `create` gyári metódus paramétereket fogadhat el, amelyeket aztán átad a konstruktornak. Adjunk például egy cikk szerzői azonosítót a `Article` osztályhoz:

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

A paramétert is hozzáadjuk a gyárhoz:

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

Mivel a konstruktorban lévő paraméter és a gyárban lévő paraméter neve megegyezik, a Nette DI automatikusan átadja őket.


Speciális definíció .[#toc-advanced-definition]
===============================================

A definíciót többsoros formában is meg lehet írni a `implement` billentyűvel:

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

Ha ilyen hosszabb formában írjuk, a `arguments` kulcsban további argumentumokat adhatunk meg a konstruktor számára, és a `setup` segítségével további konfigurációkat adhatunk meg, ugyanúgy, mint a normál szolgáltatások esetében.

Példa: ha a `create()` metódus nem fogadná el a `$authorId` paramétert, akkor a konfigurációban megadhatnánk egy fix értéket, amelyet a `Article` konstruktornak adnánk át:

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

Vagy fordítva, ha a `create()` elfogadja a `$authorId` paramétert, de az nem része a konstruktornak, hanem a `Article::setAuthorId()` módszer adja át, akkor a `setup` szakaszban hivatkoznánk rá:

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


Accessor .[#toc-accessor]
=========================

A gyárak mellett a Nette képes úgynevezett accessorokat is generálni. Az accessor egy olyan objektum, amely a `get()` metódussal rendelkezik, és egy adott szolgáltatást ad vissza a DI konténerből. Több `get()` hívás mindig ugyanazt a példányt adja vissza.

Az accessorok a lazy-loadingot hozzák a függőségekbe. Legyen egy osztályunk, amely a hibákat egy speciális adatbázisba naplózza. Ha az adatbázis-kapcsolatot függőségként adnánk át a konstruktorában, a kapcsolatot mindig létre kellene hozni, bár csak ritkán, hiba esetén használnánk, így a kapcsolat többnyire kihasználatlan maradna.
Ehelyett az osztály átadhat egy accessort, és amikor annak `get()` metódusa meghívásra kerül, csak ekkor jön létre az adatbázis-objektum:

Hogyan hozzunk létre egy accessort? Írjunk csak egy interfészt, és a Nette DI legenerálja az implementációt. Az interfésznek pontosan egy `get` nevű metódussal kell rendelkeznie, és deklarálnia kell a visszatérési típust:

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

Adja hozzá az elérőt a konfigurációs fájlhoz annak a szolgáltatásnak a definíciójával együtt, amelyet az elérő visszaad:

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

Az accessor egy `PDO` típusú szolgáltatást ad vissza, és mivel csak egy ilyen szolgáltatás van a konfigurációban, az accessor azt fogja visszaadni. Több ilyen típusú konfigurált szolgáltatás esetén a névvel megadhatja, hogy melyik legyen a visszaadandó szolgáltatás, például `- PDOAccessor(@db1)`.


Multifactory/Accessor .[#toc-multifactory-accessor]
===================================================
Eddig a factories és accessorok csak egy objektumot tudtak létrehozni vagy visszaadni. Létrehozható egy multifactory egy accessorral kombinálva is. Az ilyen multifactory osztály interfésze több metódusból állhat, amelyek neve `create<name>()` és `get<name>()`például:

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

Ahelyett, hogy több generált gyárat és accessort adna át, csak egy összetett multifactory-t adhat át.

Alternatívaként használhatja a `get()` címet is egy paraméterrel, több metódus helyett:

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

Ebben az esetben a `MultiFactory::getArticle()` ugyanazt teszi, mint a `MultiFactoryAlt::get('article')`. Az alternatív szintaxisnak azonban van néhány hátránya. Nem egyértelmű, hogy mely `$name` értékek támogatottak, és a visszatérési típus nem adható meg az interfészben, ha több különböző `$name` értéket használunk.


Definíció listával .[#toc-definition-with-a-list]
-------------------------------------------------
Így több gyárat lehet definiálni a konfigurációban: .{data-version:3.2.0}

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

Vagy a gyár definíciójában hivatkozással hivatkozhatunk meglévő szolgáltatásokra:

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


Meghatározás címkékkel .[#toc-definition-with-tags]
---------------------------------------------------

Egy másik lehetőség a multifactory definiálására a [címkék |services#Tags] használata:

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

Generált gyárak

A Nette DI képes automatikusan gyárkódot generálni a felület alapján, ami megkíméli Önt a kód írásától.

A gyár egy olyan osztály, amely objektumokat hoz létre és konfigurál. Ezért a függőségeiket is átadja nekik. Kérjük, ne keverjük össze a factory method tervezési mintával, amely a gyárak használatának egy speciális módját írja le, és nem kapcsolódik ehhez a témához.

bevezető fejezetben megmutattuk, hogyan néz ki egy ilyen gyár:

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

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

A Nette DI képes automatikusan gyárkódot generálni. Csak egy interfészt kell létrehozni, és a Nette DI generál egy implementációt. Az interfésznek pontosan egy create nevű metódussal kell rendelkeznie, és deklarálnia kell egy visszatérési típust:

interface ArticleFactory
{
	function create(): Article;
}

Tehát a ArticleFactory gyárnak van egy create metódusa, amely létrehozza a Article objektumokat. A Article osztály például a következőképpen nézhet ki:

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

Adja hozzá a gyárat a konfigurációs fájlhoz:

services:
	- ArticleFactory

A Nette DI létrehozza a megfelelő gyár implementációját.

Így a gyárat használó kódban az objektumot interfész szerint kérjük, és a Nette DI a generált implementációt használja:

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

	public function foo()
	{
		// hagyjuk, hogy a gyár létrehozzon egy objektumot
		$article = $this->articleFactory->create();
	}
}

Paraméteres gyár

A create gyári metódus paramétereket fogadhat el, amelyeket aztán átad a konstruktornak. Adjunk például egy cikk szerzői azonosítót a Article osztályhoz:

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

A paramétert is hozzáadjuk a gyárhoz:

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

Mivel a konstruktorban lévő paraméter és a gyárban lévő paraméter neve megegyezik, a Nette DI automatikusan átadja őket.

Speciális definíció

A definíciót többsoros formában is meg lehet írni a implement billentyűvel:

services:
	articleFactory:
		implement: ArticleFactory

Ha ilyen hosszabb formában írjuk, a arguments kulcsban további argumentumokat adhatunk meg a konstruktor számára, és a setup segítségével további konfigurációkat adhatunk meg, ugyanúgy, mint a normál szolgáltatások esetében.

Példa: ha a create() metódus nem fogadná el a $authorId paramétert, akkor a konfigurációban megadhatnánk egy fix értéket, amelyet a Article konstruktornak adnánk át:

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

Vagy fordítva, ha a create() elfogadja a $authorId paramétert, de az nem része a konstruktornak, hanem a Article::setAuthorId() módszer adja át, akkor a setup szakaszban hivatkoznánk rá:

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

Accessor

A gyárak mellett a Nette képes úgynevezett accessorokat is generálni. Az accessor egy olyan objektum, amely a get() metódussal rendelkezik, és egy adott szolgáltatást ad vissza a DI konténerből. Több get() hívás mindig ugyanazt a példányt adja vissza.

Az accessorok a lazy-loadingot hozzák a függőségekbe. Legyen egy osztályunk, amely a hibákat egy speciális adatbázisba naplózza. Ha az adatbázis-kapcsolatot függőségként adnánk át a konstruktorában, a kapcsolatot mindig létre kellene hozni, bár csak ritkán, hiba esetén használnánk, így a kapcsolat többnyire kihasználatlan maradna. Ehelyett az osztály átadhat egy accessort, és amikor annak get() metódusa meghívásra kerül, csak ekkor jön létre az adatbázis-objektum:

Hogyan hozzunk létre egy accessort? Írjunk csak egy interfészt, és a Nette DI legenerálja az implementációt. Az interfésznek pontosan egy get nevű metódussal kell rendelkeznie, és deklarálnia kell a visszatérési típust:

interface PDOAccessor
{
	function get(): PDO;
}

Adja hozzá az elérőt a konfigurációs fájlhoz annak a szolgáltatásnak a definíciójával együtt, amelyet az elérő visszaad:

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

Az accessor egy PDO típusú szolgáltatást ad vissza, és mivel csak egy ilyen szolgáltatás van a konfigurációban, az accessor azt fogja visszaadni. Több ilyen típusú konfigurált szolgáltatás esetén a névvel megadhatja, hogy melyik legyen a visszaadandó szolgáltatás, például - PDOAccessor(@db1).

Multifactory/Accessor

Eddig a factories és accessorok csak egy objektumot tudtak létrehozni vagy visszaadni. Létrehozható egy multifactory egy accessorral kombinálva is. Az ilyen multifactory osztály interfésze több metódusból állhat, amelyek neve create<name>() és get<name>()például:

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

Ahelyett, hogy több generált gyárat és accessort adna át, csak egy összetett multifactory-t adhat át.

Alternatívaként használhatja a get() címet is egy paraméterrel, több metódus helyett:

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

Ebben az esetben a MultiFactory::getArticle() ugyanazt teszi, mint a MultiFactoryAlt::get('article'). Az alternatív szintaxisnak azonban van néhány hátránya. Nem egyértelmű, hogy mely $name értékek támogatottak, és a visszatérési típus nem adható meg az interfészben, ha több különböző $name értéket használunk.

Definíció listával

Így több gyárat lehet definiálni a konfigurációban:

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

Vagy a gyár definíciójában hivatkozással hivatkozhatunk meglévő szolgáltatásokra:

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

Meghatározás címkékkel

Egy másik lehetőség a multifactory definiálására a címkék használata:

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