Nette Documentation Preview

syntax
Modell
******

Ahogy az alkalmazás növekszik, hamarosan rájövünk, hogy különböző helyeken, különböző presenterekben hasonló adatbázis-műveleteket kell végrehajtanunk. Például a legújabb publikált cikkek lekérése. Ha az alkalmazást például úgy fejlesztjük tovább, hogy a cikkeknél hozzáadunk egy jelzőt, hogy vázlatban van-e, akkor végig kell mennünk az alkalmazás összes olyan helyén, ahol cikkeket kérünk le az adatbázisból, és hozzá kell adnunk a where feltételt, hogy csak a nem vázlatban lévő cikkeket válasszuk ki.

Ebben a pillanatban a közvetlen adatbázis-kezelés elégtelenné válik, és hasznosabb lesz egy új függvénnyel segíteni magunkon, amely a publikált cikkeket fogja visszaadni nekünk. És ha később hozzáadunk egy másik feltételt, például hogy ne jelenjenek meg a jövőbeli dátummal rendelkező cikkek, a kódot csak egy helyen módosítjuk.

A funkciót például a `PostFacade` osztályba helyezzük, és `getPublicArticles()`-nak nevezzük el.

Az `app/Model/` könyvtárban létrehozzuk a `PostFacade` modell osztályunkat, amely a cikkekkel fog foglalkozni:

```php .{file:app/Model/PostFacade.php}
<?php
namespace App\Model;

use Nette;

final class PostFacade
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	public function getPublicArticles()
	{
		return $this->database
			->table('posts')
			->where('created_at < ', new \DateTime)
			->order('created_at DESC');
	}
}
```

Az osztályban a konstruktor segítségével kérjük át az adatbázis [api:Nette\Database\Explorer]-t. Kihasználjuk a [DI konténer |dependency-injection:passing-dependencies] erejét.

Váltsunk a `HomePresenter`-re, amelyet úgy módosítunk, hogy megszabadulunk a `Nette\Database\Explorer` függőségtől, és lecseréljük az új osztályunktól való új függőségre.

```php .{file:app/Presentation/Home/HomePresenter.php}
<?php
namespace App\Presentation\Home;

use App\Model\PostFacade;
use Nette;

final class HomePresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private PostFacade $facade,
	) {
	}

	public function renderDefault(): void
	{
		$this->template->posts = $this->facade
			->getPublicArticles()
			->limit(5);
	}
}
```

A use szakaszban `App\Model\PostFacade` van, így a PHP kódban a jelölést lerövidíthetjük `PostFacade`-ra. Ezt az objektumot kérjük a konstruktorban, beírjuk a `$facade` property-be, és használjuk a renderDefault metódusban.

Már csak az utolsó lépés van hátra, megtanítani a DI konténert, hogy ezt az objektumot előállítsa. Ez általában úgy történik, hogy a `config/services.neon` fájl `services` szakaszába hozzáadunk egy felsorolásjelet, megadjuk az osztály teljes nevét és a konstruktor paramétereit. Ezzel regisztráljuk, és az objektumot ezután **szolgáltatásnak** nevezzük. Az [autowiring |dependency-injection:autowiring] nevű varázslatnak köszönhetően általában nem kell megadnunk a konstruktor paramétereit, mert a DI felismeri és átadja őket. Így elegendő lenne csak az osztály nevét megadni:

```neon .{file:config/services.neon}
...

services:
	- App\Model\PostFacade
```

Azonban ezt a sort sem kell hozzáadnia. A `services.neon` elején a `search` szakaszban definiálva van, hogy minden `-Facade` vagy `-Factory` végződésű osztályt a DI maga keres meg, ami a `PostFacade` esetében is így van.


Összegzés
=========

A `PostFacade` osztály a konstruktorában kéri a `Nette\Database\Explorer` átadását, és mivel ez az osztály regisztrálva van a DI konténerben, a konténer létrehozza ezt a példányt és átadja neki. A DI így létrehozza nekünk a `PostFacade` példányt, és átadja a konstruktorban a HomePresenter osztálynak, amely kérte. Ilyen matrjoska. :) Mindenki csak megmondja, mit akar, és nem érdekli, hol és hogyan jön létre valami. A létrehozásról a DI konténer gondoskodik.

.[note]
Itt többet olvashat a [dependency injection |dependency-injection:introduction]-ről és a [konfigurációról |nette:configuring].

{{priority: -1}}
{{sitename: Nette Quickstart}}

Modell

Ahogy az alkalmazás növekszik, hamarosan rájövünk, hogy különböző helyeken, különböző presenterekben hasonló adatbázis-műveleteket kell végrehajtanunk. Például a legújabb publikált cikkek lekérése. Ha az alkalmazást például úgy fejlesztjük tovább, hogy a cikkeknél hozzáadunk egy jelzőt, hogy vázlatban van-e, akkor végig kell mennünk az alkalmazás összes olyan helyén, ahol cikkeket kérünk le az adatbázisból, és hozzá kell adnunk a where feltételt, hogy csak a nem vázlatban lévő cikkeket válasszuk ki.

Ebben a pillanatban a közvetlen adatbázis-kezelés elégtelenné válik, és hasznosabb lesz egy új függvénnyel segíteni magunkon, amely a publikált cikkeket fogja visszaadni nekünk. És ha később hozzáadunk egy másik feltételt, például hogy ne jelenjenek meg a jövőbeli dátummal rendelkező cikkek, a kódot csak egy helyen módosítjuk.

A funkciót például a PostFacade osztályba helyezzük, és getPublicArticles()-nak nevezzük el.

Az app/Model/ könyvtárban létrehozzuk a PostFacade modell osztályunkat, amely a cikkekkel fog foglalkozni:

<?php
namespace App\Model;

use Nette;

final class PostFacade
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	public function getPublicArticles()
	{
		return $this->database
			->table('posts')
			->where('created_at < ', new \DateTime)
			->order('created_at DESC');
	}
}

Az osztályban a konstruktor segítségével kérjük át az adatbázis Nette\Database\Explorer-t. Kihasználjuk a DI konténer erejét.

Váltsunk a HomePresenter-re, amelyet úgy módosítunk, hogy megszabadulunk a Nette\Database\Explorer függőségtől, és lecseréljük az új osztályunktól való új függőségre.

<?php
namespace App\Presentation\Home;

use App\Model\PostFacade;
use Nette;

final class HomePresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private PostFacade $facade,
	) {
	}

	public function renderDefault(): void
	{
		$this->template->posts = $this->facade
			->getPublicArticles()
			->limit(5);
	}
}

A use szakaszban App\Model\PostFacade van, így a PHP kódban a jelölést lerövidíthetjük PostFacade-ra. Ezt az objektumot kérjük a konstruktorban, beírjuk a $facade property-be, és használjuk a renderDefault metódusban.

Már csak az utolsó lépés van hátra, megtanítani a DI konténert, hogy ezt az objektumot előállítsa. Ez általában úgy történik, hogy a config/services.neon fájl services szakaszába hozzáadunk egy felsorolásjelet, megadjuk az osztály teljes nevét és a konstruktor paramétereit. Ezzel regisztráljuk, és az objektumot ezután szolgáltatásnak nevezzük. Az autowiring nevű varázslatnak köszönhetően általában nem kell megadnunk a konstruktor paramétereit, mert a DI felismeri és átadja őket. Így elegendő lenne csak az osztály nevét megadni:

...

services:
	- App\Model\PostFacade

Azonban ezt a sort sem kell hozzáadnia. A services.neon elején a search szakaszban definiálva van, hogy minden -Facade vagy -Factory végződésű osztályt a DI maga keres meg, ami a PostFacade esetében is így van.

Összegzés

A PostFacade osztály a konstruktorában kéri a Nette\Database\Explorer átadását, és mivel ez az osztály regisztrálva van a DI konténerben, a konténer létrehozza ezt a példányt és átadja neki. A DI így létrehozza nekünk a PostFacade példányt, és átadja a konstruktorban a HomePresenter osztálynak, amely kérte. Ilyen matrjoska. :) Mindenki csak megmondja, mit akar, és nem érdekli, hol és hogyan jön létre valami. A létrehozásról a DI konténer gondoskodik.

Itt többet olvashat a dependency injection-ről és a konfigurációról.