Nette Documentation Preview

syntax
Model
*****

S tím, jak aplikace roste, brzy zjistíme, že na různých místech, v různých presenterech, potřebujeme provádět podobné operace s databází. Například získávat nejnovější publikované články. Když aplikaci vylepšíme třeba tím, že u článků přidáme příznak, zda je rozepsaný, musíme potom projít i všechna místa v aplikaci, kde se články z databáze získávají a doplnit podmínku where, aby se vybíraly jen články nerozepsané.

V ten moment se přímá práce s databází stává nedostatečnou a bude šikovnější si vypomoci novou funkcí, která nám publikované články bude vracet. A když později přidáme další podmínku, například že se nemají zobrazovat články s budoucím datem, upravíme kód jen na jednom místě.

Funkci umístíme třeba do třídy `PostFacade` a nazveme ji `getPublicArticles()`.

V adresáři `app/Model/` vytvoříme naši modelovou třídu `PostFacade`, která se nám bude starat o články:

```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');
	}
}
```

Ve třídě si pomocí konstruktoru necháme předat databázový Explorer:[api:Nette\Database\Explorer]. Využijeme tak síly [DI containeru|dependency-injection:passing-dependencies].

Přepneme se na `HomePresenter`, který upravíme tak, že se zbavíme závislosti na `Nette\Database\Explorer` a nahradíme za novou závislost na naší nové třídě.

```php .{file:app/UI/Home/HomePresenter.php}
<?php
namespace App\UI\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);
	}
}
```

V sekci use máme `App\Model\PostFacade`, tak si můžeme zápis v PHP kódu zkrátit na `PostFacade`. O tento objekt požádáme v konstruktoru, zapíšeme jej do vlastnosti `$facade` a použijeme v metodě renderDefault.

Zbývá poslední krok a to naučit DI container tento objekt vyrábět. To se obvykle dělá tak, že do souboru `config/services.neon` v sekci `services` přidáme odrážku, uvedeme plný název třídy a parametry konstruktoru.
Tím ji takzvaně zaregistrujeme a objekt se pak nazývá **služba**. Díky kouzlu jménem [autowiring |dependency-injection:autowiring] nemusíme většinou parametry konstruktoru uvádět, protože DI je samo rozpozná a předá. Stačilo by tak uvést jen název třídy:

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

services:
	- App\Model\PostFacade
```

Nicméně ani tento řádek přidávat nemusíte. V sekci `search` na začátku `services.neon` je definováno, že všechny třídy končíci slovem `-Facade` nebo `-Factory` si DI dohledá samo, což je i případ `PostFacade`.


Shrnutí
=======

Třída `PostFacade` si v konstruktoru řekne o předání `Nette\Database\Explorer` a jelikož je tato třída v DI containeru zaregistrovaná, kontejner tuto instanci vytvoří a předá ji. DI za nás takto vytvoří instanci `PostFacade` a předá ji v konstruktoru třídě HomePresenter, který si o něj požádal. Taková matrjoška. :) Všichni si jen říkají co chtějí a nezajímají se o to, kde se co a jak vytváří. O vytvoření se stará DI container.

.[note]
Zde si můžete přečíst více o [dependency injection |dependency-injection:introduction] a [konfiguraci |nette:configuring].

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

Model

S tím, jak aplikace roste, brzy zjistíme, že na různých místech, v různých presenterech, potřebujeme provádět podobné operace s databází. Například získávat nejnovější publikované články. Když aplikaci vylepšíme třeba tím, že u článků přidáme příznak, zda je rozepsaný, musíme potom projít i všechna místa v aplikaci, kde se články z databáze získávají a doplnit podmínku where, aby se vybíraly jen články nerozepsané.

V ten moment se přímá práce s databází stává nedostatečnou a bude šikovnější si vypomoci novou funkcí, která nám publikované články bude vracet. A když později přidáme další podmínku, například že se nemají zobrazovat články s budoucím datem, upravíme kód jen na jednom místě.

Funkci umístíme třeba do třídy PostFacade a nazveme ji getPublicArticles().

V adresáři app/Model/ vytvoříme naši modelovou třídu PostFacade, která se nám bude starat o články:

<?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');
	}
}

Ve třídě si pomocí konstruktoru necháme předat databázový Explorer. Využijeme tak síly DI containeru.

Přepneme se na HomePresenter, který upravíme tak, že se zbavíme závislosti na Nette\Database\Explorer a nahradíme za novou závislost na naší nové třídě.

<?php
namespace App\UI\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);
	}
}

V sekci use máme App\Model\PostFacade, tak si můžeme zápis v PHP kódu zkrátit na PostFacade. O tento objekt požádáme v konstruktoru, zapíšeme jej do vlastnosti $facade a použijeme v metodě renderDefault.

Zbývá poslední krok a to naučit DI container tento objekt vyrábět. To se obvykle dělá tak, že do souboru config/services.neon v sekci services přidáme odrážku, uvedeme plný název třídy a parametry konstruktoru. Tím ji takzvaně zaregistrujeme a objekt se pak nazývá služba. Díky kouzlu jménem autowiring nemusíme většinou parametry konstruktoru uvádět, protože DI je samo rozpozná a předá. Stačilo by tak uvést jen název třídy:

...

services:
	- App\Model\PostFacade

Nicméně ani tento řádek přidávat nemusíte. V sekci search na začátku services.neon je definováno, že všechny třídy končíci slovem -Facade nebo -Factory si DI dohledá samo, což je i případ PostFacade.

Shrnutí

Třída PostFacade si v konstruktoru řekne o předání Nette\Database\Explorer a jelikož je tato třída v DI containeru zaregistrovaná, kontejner tuto instanci vytvoří a předá ji. DI za nás takto vytvoří instanci PostFacade a předá ji v konstruktoru třídě HomePresenter, který si o něj požádal. Taková matrjoška. :) Všichni si jen říkají co chtějí a nezajímají se o to, kde se co a jak vytváří. O vytvoření se stará DI container.

Zde si můžete přečíst více o dependency injection a konfiguraci.