Model | První aplikace

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. Umístíme ji například do souboru PostFacade.php.

namespace App\Model;

use Nette;

final class PostFacade
{
	use Nette\SmartObject;

	private Nette\Database\Explorer $database;

	public function __construct(Nette\Database\Explorer $database)
	{
		$this->database = $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.

Ještě do souboru config/services.neon v sekci services přidáme řádek s celým názvem třídy:

services:
	- App\Router\RouterFactory::createRouter
	- App\Model\PostFacade

Tím DI containeru říkáme: „Kdyby někdo chtěl instanci této třídy, tak víš kde ji hledat. Předej této instanci vše, co potřebuje k životu a připrav nám ji pro použití v dalších třídách.“ Takto registrovaná třída se pak nazývá služba.

Přepneme se do HomepagePresenter.php, 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ě.

namespace App\Presenters;

use App\Model\PostFacade;
use Nette;

final class HomepagePresenter extends Nette\Application\UI\Presenter
{
	private PostFacade $facade;

	public function __construct(PostFacade $facade)
	{
		$this->facade = $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 (nebojte, i v komentářích to funguje a vaše chytré IDE by si s tím mělo poradit).

V konstruktoru si požádáme o PostFacade, který si přiřadíme do vlastnosti $facade a v metodě renderDefault zavoláme metodu getPublicArticles(). Nad výsledkem této funkce zavoláme ještě metodu limit(5);

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 PostFacadea a předá ho v konstruktoru třídě HomepagePresenter, 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.