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.