Model

Pe măsură ce aplicația crește, vom descoperi curând că în diferite locuri, în diferiți presenteri, avem nevoie să efectuăm operații similare cu baza de date. De exemplu, să obținem cele mai recente articole publicate. Dacă îmbunătățim aplicația, de exemplu, adăugând un indicator la articole dacă sunt în curs de redactare, trebuie apoi să parcurgem toate locurile din aplicație unde se obțin articole din baza de date și să adăugăm condiția where, pentru a selecta doar articolele care nu sunt în curs de redactare.

În acel moment, lucrul direct cu baza de date devine insuficient și va fi mai inteligent să ne ajutăm cu o nouă funcție care ne va returna articolele publicate. Și dacă ulterior adăugăm o altă condiție, de exemplu, că nu trebuie afișate articolele cu dată viitoare, vom modifica codul doar într-un singur loc.

Vom plasa funcția, de exemplu, în clasa PostFacade și o vom numi getPublicArticles().

În directorul app/Model/ vom crea clasa noastră de model PostFacade, care se va ocupa de articole:

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

În clasă, prin intermediul constructorului, vom solicita transmiterea bazei de date Explorer. Vom folosi astfel puterea containerului DI.

Trecem la HomePresenter, pe care îl vom modifica astfel încât să eliminăm dependența de Nette\Database\Explorer și să o înlocuim cu noua dependență de clasa noastră nouă.

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

În secțiunea use avem App\Model\PostFacade, așa că putem scurta notația în codul PHP la PostFacade. Solicităm acest obiect în constructor, îl scriem în proprietatea $facade și îl folosim în metoda renderDefault.

Rămâne ultimul pas și anume să învățăm containerul DI să producă acest obiect. Acest lucru se face de obicei adăugând un element cu bulină în fișierul config/services.neon în secțiunea services, specificând numele complet al clasei și parametrii constructorului. Astfel o înregistrăm, iar obiectul se numește apoi serviciu. Datorită magiei numite autowiring, de cele mai multe ori nu trebuie să specificăm parametrii constructorului, deoarece DI îi recunoaște și îi transmite automat. Ar fi suficient deci să specificăm doar numele clasei:

...

services:
	- App\Model\PostFacade

Cu toate acestea, nici această linie nu trebuie adăugată. În secțiunea search de la începutul services.neon este definit că toate clasele care se termină cu cuvântul -Facade sau -Factory vor fi găsite automat de DI, ceea ce este și cazul PostFacade.

Rezumat

Clasa PostFacade solicită în constructor transmiterea Nette\Database\Explorer și, deoarece această clasă este înregistrată în containerul DI, containerul creează această instanță și o transmite. DI creează astfel pentru noi instanța PostFacade și o transmite în constructor clasei HomePresenter, care a solicitat-o. Un fel de păpușă Matrioșka. :) Toată lumea spune doar ce vrea și nu se interesează unde și cum se creează ceva. De creare se ocupă containerul DI.

Aici puteți citi mai multe despre injecția de dependențe și configurare.