Nette Documentation Preview

syntax
Model
*****

Wraz z rozwojem aplikacji szybko okazuje się, że musimy wykonywać podobne operacje na bazie danych w różnych miejscach, w różnych prezenterach. Na przykład, aby pobrać najnowsze opublikowane artykuły. Jeśli wzbogacimy aplikację, dodając na przykład flagę dla artykułów, aby wskazać, czy są one niepublikowane, musimy wtedy przejść przez wszystkie miejsca w aplikacji, gdzie artykuły są pobierane z bazy danych i dodać warunek where, aby wybrać tylko niepublikowane artykuły.

W tym momencie praca bezpośrednio z bazą danych staje się niewystarczająca i przydatne będzie użycie nowej funkcji do zwrócenia opublikowanych artykułów. A jeśli później dodamy kolejny warunek, np. że artykuły z przyszłą datą nie powinny być wyświetlane, zmodyfikujemy kod tylko w jednym miejscu.

Na przykład umieść funkcję w klasie `PostFacade` i nazwij ją `getPublicArticles()`.

W katalogu `app/Model/` stworzymy naszą klasę modelową `PostFacade`, która zajmie się artykułami:

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

W klasie będziemy mieli konstruktor przekazujący eksplorator bazy danych:[api:Nette\Database\Explorer]. Wykorzystamy moc [kontenera DI |dependency-injection:passing-dependencies].

Przechodzimy na stronę `HomePresenter`, którą modyfikujemy pozbywając się zależności od `Nette\Database\Explorer` i zastępując ją zależnością od naszej nowej klasy.

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

W sekcji use mamy `App\Model\PostFacade`, więc możemy skrócić zapis kodu PHP do `PostFacade`. Będziemy żądać tego obiektu w konstruktorze, zapisywać go do właściwości `$facade` i używać w metodzie renderDefault.

Pozostał ostatni krok - nauczenie kontenera DI produkowania tego obiektu. Zwykle robi się to poprzez dodanie punktu wypunktowania do pliku `config/services.neon` w sekcji `services`, podając pełną nazwę klasy i parametry konstruktora.
To rejestruje go, że tak powiem, a obiekt jest następnie nazywany **serwisem**. Dzięki magicznej sztuczce zwanej [autowiring |dependency-injection:autowiring], zazwyczaj nie musimy podawać parametrów konstruktora, ponieważ DI sam je rozpozna i przekaże. Tak więc wystarczyłoby po prostu podać nazwę klasy:

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

services:
	- App\Model\PostFacade
```

Nie musisz jednak dodawać również tej linii. Sekcja `search` na początku `services.neon` definiuje, że wszystkie klasy kończące się na `-Facade` lub `-Factory` będą wyszukiwane przez DI, co dotyczy również `PostFacade`.


Streszczenie. .[#toc-summary]
=============================

Klasa `PostFacade` prosi konstruktora o przekazanie `Nette\Database\Explorer`, a ponieważ ta klasa jest zarejestrowana w kontenerze DI, kontener tworzy i przekazuje tę instancję. DI tworzy więc dla nas instancję `PostFacade` i przekazuje ją w konstruktorze do klasy HomePresenter, która jej zażądała. To jest matryca. :) Każdy mówi tylko to, co chce i nie przejmuje się tym, gdzie co powstaje i jak. Kontener DI zajmuje się tworzeniem.

.[note]
Możesz przeczytać więcej o [wtrysku zależności |dependency-injection:introduction] i [konfiguracji |nette:configuring] tutaj.

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

Model

Wraz z rozwojem aplikacji szybko okazuje się, że musimy wykonywać podobne operacje na bazie danych w różnych miejscach, w różnych prezenterach. Na przykład, aby pobrać najnowsze opublikowane artykuły. Jeśli wzbogacimy aplikację, dodając na przykład flagę dla artykułów, aby wskazać, czy są one niepublikowane, musimy wtedy przejść przez wszystkie miejsca w aplikacji, gdzie artykuły są pobierane z bazy danych i dodać warunek where, aby wybrać tylko niepublikowane artykuły.

W tym momencie praca bezpośrednio z bazą danych staje się niewystarczająca i przydatne będzie użycie nowej funkcji do zwrócenia opublikowanych artykułów. A jeśli później dodamy kolejny warunek, np. że artykuły z przyszłą datą nie powinny być wyświetlane, zmodyfikujemy kod tylko w jednym miejscu.

Na przykład umieść funkcję w klasie PostFacade i nazwij ją getPublicArticles().

W katalogu app/Model/ stworzymy naszą klasę modelową PostFacade, która zajmie się artykułami:

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

W klasie będziemy mieli konstruktor przekazujący eksplorator bazy danych. Wykorzystamy moc kontenera DI.

Przechodzimy na stronę HomePresenter, którą modyfikujemy pozbywając się zależności od Nette\Database\Explorer i zastępując ją zależnością od naszej nowej klasy.

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

W sekcji use mamy App\Model\PostFacade, więc możemy skrócić zapis kodu PHP do PostFacade. Będziemy żądać tego obiektu w konstruktorze, zapisywać go do właściwości $facade i używać w metodzie renderDefault.

Pozostał ostatni krok – nauczenie kontenera DI produkowania tego obiektu. Zwykle robi się to poprzez dodanie punktu wypunktowania do pliku config/services.neon w sekcji services, podając pełną nazwę klasy i parametry konstruktora. To rejestruje go, że tak powiem, a obiekt jest następnie nazywany serwisem. Dzięki magicznej sztuczce zwanej autowiring, zazwyczaj nie musimy podawać parametrów konstruktora, ponieważ DI sam je rozpozna i przekaże. Tak więc wystarczyłoby po prostu podać nazwę klasy:

...

services:
	- App\Model\PostFacade

Nie musisz jednak dodawać również tej linii. Sekcja search na początku services.neon definiuje, że wszystkie klasy kończące się na -Facade lub -Factory będą wyszukiwane przez DI, co dotyczy również PostFacade.

Streszczenie.

Klasa PostFacade prosi konstruktora o przekazanie Nette\Database\Explorer, a ponieważ ta klasa jest zarejestrowana w kontenerze DI, kontener tworzy i przekazuje tę instancję. DI tworzy więc dla nas instancję PostFacade i przekazuje ją w konstruktorze do klasy HomePresenter, która jej zażądała. To jest matryca. :) Każdy mówi tylko to, co chce i nie przejmuje się tym, gdzie co powstaje i jak. Kontener DI zajmuje się tworzeniem.

Możesz przeczytać więcej o wtrysku zależnościkonfiguracji tutaj.