Nette Documentation Preview

syntax
Modell
******

Ahogy alkalmazásunk növekszik, hamarosan rájövünk, hogy hasonló adatbázisműveleteket kell végrehajtanunk különböző helyeken és különböző prezenterekben, például a legújabb megjelent cikkek megszerzéséhez. Ha úgy fejlesztjük az alkalmazásunkat, hogy a cikkekhez hozzáadunk egy flaget, amely a folyamatban lévő cikkek állapotát jelzi, akkor is végig kell mennünk az alkalmazásunk összes helyszínén, és hozzá kell adnunk egy where záradékot, hogy csak a kész cikkek legyenek kiválasztva.

Ezen a ponton az adatbázissal való közvetlen munka elégtelenné válik, és okosabb lesz egy új függvénnyel segíteni magunkat, amely visszaadja a megjelent cikkeket. Ha pedig később újabb záradékot adunk hozzá (például, hogy ne jelenítsünk meg jövőbeni dátumú cikkeket), akkor csak egy helyen szerkesztjük a kódunkat.

A függvényt a `PostFacade` osztályba helyezzük, és `getPublicArticles()` névre kereszteljük.

Létrehozzuk a `PostFacade` modellosztályunkat a `app/Model/` könyvtárban, hogy gondoskodjon a cikkeinkről:

```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 átadjuk az adatbázis Explorer-t:[api:Nette\Database\Explorer]. Ezzel kihasználjuk a [DI konténer |dependency-injection:passing-dependencies] erejét.

Átváltunk a `HomePresenter` -ra, amelyet úgy szerkesztünk, hogy megszabadulunk a `Nette\Database\Explorer` függőségtől, és azt az új osztályunk függőségével helyettesítjük.

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

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 használati szakaszban a `App\Model\PostFacade` címet használjuk, így a PHP-kódot lerövidíthetjük a `PostFacade` címre. Ezt az objektumot a konstruktorban kérjük, a `$facade` tulajdonságba írjuk, és a renderDefault metódusban használjuk.

Az utolsó hátralévő lépés az, hogy megtanítjuk a DI konténert, hogy ezt az objektumot előállítsa. Ez általában úgy történik, hogy a `config/services.neon` fájlban a `services` szakaszban egy bullet pointot adunk hozzá a fájlhoz, megadva a teljes osztálynevet és a konstruktor paramétereit.
Ezzel úgymond regisztráljuk, és az objektumot ezután **service**-nek hívjuk. 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 automatikusan á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áadni. A `search` szakaszban, a `services.neon` elején van definiálva, hogy a `-Facade` vagy `-Factory` végződésű osztályokat a DI automatikusan megkeresi, ami a `PostFacade` esetében is így van.


Összefoglaló .[#toc-summary]
============================

A `PostFacade` osztály egy konstruktorban kéri a `Nette\Database\Explorer` címet, é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. A DI így létrehoz nekünk egy `PostFacade` példányt, és egy konstruktorban átadja azt a HomePresenter osztálynak, amelyik ezt kérte. Afféle Matrjoska baba kód :) Minden komponens csak azt kéri, amire szüksége van, és nem érdekli őket, hogy hol és hogyan jön létre. A létrehozást a DI konténer kezeli.

.[note]
Itt olvashatsz többet a [függőségi injektálásról |dependency-injection:introduction], és a [konfigurációról |nette:configuring].

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

Modell

Ahogy alkalmazásunk növekszik, hamarosan rájövünk, hogy hasonló adatbázisműveleteket kell végrehajtanunk különböző helyeken és különböző prezenterekben, például a legújabb megjelent cikkek megszerzéséhez. Ha úgy fejlesztjük az alkalmazásunkat, hogy a cikkekhez hozzáadunk egy flaget, amely a folyamatban lévő cikkek állapotát jelzi, akkor is végig kell mennünk az alkalmazásunk összes helyszínén, és hozzá kell adnunk egy where záradékot, hogy csak a kész cikkek legyenek kiválasztva.

Ezen a ponton az adatbázissal való közvetlen munka elégtelenné válik, és okosabb lesz egy új függvénnyel segíteni magunkat, amely visszaadja a megjelent cikkeket. Ha pedig később újabb záradékot adunk hozzá (például, hogy ne jelenítsünk meg jövőbeni dátumú cikkeket), akkor csak egy helyen szerkesztjük a kódunkat.

A függvényt a PostFacade osztályba helyezzük, és getPublicArticles() névre kereszteljük.

Létrehozzuk a PostFacade modellosztályunkat a app/Model/ könyvtárban, hogy gondoskodjon a cikkeinkről:

<?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 átadjuk az adatbázis Explorer-t. Ezzel kihasználjuk a DI konténer erejét.

Átváltunk a HomePresenter -ra, amelyet úgy szerkesztünk, hogy megszabadulunk a Nette\Database\Explorer függőségtől, és azt az új osztályunk függőségével helyettesítjük.

<?php
namespace App\Presenters;

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 használati szakaszban a App\Model\PostFacade címet használjuk, így a PHP-kódot lerövidíthetjük a PostFacade címre. Ezt az objektumot a konstruktorban kérjük, a $facade tulajdonságba írjuk, és a renderDefault metódusban használjuk.

Az utolsó hátralévő lépés az, hogy megtanítjuk a DI konténert, hogy ezt az objektumot előállítsa. Ez általában úgy történik, hogy a config/services.neon fájlban a services szakaszban egy bullet pointot adunk hozzá a fájlhoz, megadva a teljes osztálynevet és a konstruktor paramétereit. Ezzel úgymond regisztráljuk, és az objektumot ezután service-nek hívjuk. Az autowiring nevű varázslatnak köszönhetően általában nem kell megadnunk a konstruktor paramétereit, mert a DI felismeri és automatikusan átadja őket. Így elegendő lenne csak az osztály nevét megadni:

...

services:
	- App\Model\PostFacade

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

Összefoglaló

A PostFacade osztály egy konstruktorban kéri a Nette\Database\Explorer címet, é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. A DI így létrehoz nekünk egy PostFacade példányt, és egy konstruktorban átadja azt a HomePresenter osztálynak, amelyik ezt kérte. Afféle Matrjoska baba kód :) Minden komponens csak azt kéri, amire szüksége van, és nem érdekli őket, hogy hol és hogyan jön létre. A létrehozást a DI konténer kezeli.

Itt olvashatsz többet a függőségi injektálásról, és a konfigurációról.