Model

Ko aplikacija raste, bomo kmalu ugotovili, da na različnih mestih, v različnih presenterjih, potrebujemo izvajati podobne operacije s podatkovno bazo. Na primer pridobivati najnovejše objavljene članke. Ko aplikacijo izboljšamo, na primer tako, da pri člankih dodamo zastavico, ali je osnutek, moramo potem pregledati tudi vsa mesta v aplikaciji, kjer se članki pridobivajo iz podatkovne baze, in dopolniti pogoj where, da se izbirajo samo članki, ki niso osnutki.

V tistem trenutku neposredno delo s podatkovno bazo postane nezadostno in bo bolj priročno, če si pomagamo z novo funkcijo, ki nam bo vračala objavljene članke. In ko kasneje dodamo še en pogoj, na primer da se ne prikazujejo članki z datumom v prihodnosti, uredimo kodo samo na enem mestu.

Funkcijo postavimo na primer v razred PostFacade in jo poimenujemo getPublicArticles().

V imeniku app/Model/ ustvarimo naš modelni razred PostFacade, ki nam bo skrbel za članke:

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

V razredu si s pomočjo konstruktorja pustimo predati podatkovni Explorer. Izkoristimo tako moč DI vsebnika.

Preklopimo na HomePresenter, ki ga uredimo tako, da se znebimo odvisnosti od Nette\Database\Explorer in jo nadomestimo z novo odvisnostjo od našega novega razreda.

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

V sekciji use imamo App\Model\PostFacade, tako da lahko zapis v PHP kodi skrajšamo na PostFacade. Za ta objekt zaprosimo v konstruktorju, ga zapišemo v lastnost $facade in uporabimo v metodi renderDefault.

Ostaja še zadnji korak, in sicer naučiti DI vsebnik ta objekt izdelovati. To se običajno naredi tako, da v datoteko config/services.neon v sekcijo services dodamo alinejo, navedemo polno ime razreda in parametre konstruktorja. S tem ga tako imenovano registriramo in objekt se potem imenuje storitev. Zahvaljujoč čarovniji imenovani autowiring nam večinoma ni treba navajati parametrov konstruktorja, ker jih DI sam prepozna in preda. Zadostovalo bi torej navesti samo ime razreda:

...

services:
	- App\Model\PostFacade

Vendar niti te vrstice ni treba dodajati. V sekciji search na začetku services.neon je definirano, da vse razrede, ki se končajo z besedo -Facade ali -Factory, DI poišče sam, kar je tudi primer PostFacade.

Povzetek

Razred PostFacade si v konstruktorju zahteva predajo Nette\Database\Explorer in ker je ta razred v DI vsebniku registriran, vsebnik to instanco ustvari in jo preda. DI za nas tako ustvari instanco PostFacade in jo preda v konstruktorju razredu HomePresenter, ki je zanjo zaprosil. Takšna matrjoška. :) Vsi si samo povedo, kaj želijo, in jih ne zanima, kje se kaj in kako ustvarja. Za ustvarjanje skrbi DI vsebnik.

Tukaj si lahko preberete več o dependency injection in konfiguraciji.