Model

Uygulamamız büyüdükçe, benzer veritabanı işlemlerini çeşitli yerlerde ve çeşitli presenter'larda yapmamız gerektiğini kısa sürede fark ederiz; örneğin en son yayımlanan gönderileri almak. Uygulamamızı geliştirir, örneğin gönderilere taslak olup olmadıklarını gösteren bir bayrak eklersek, uygulamamızda gönderilerin veritabanından alındığı tüm yerleri de gözden geçirip yalnızca taslak olmayan gönderilerin seçilmesini sağlayacak bir where koşulu eklememiz gerekir.

Bu noktada doğrudan veritabanıyla çalışmak yetersizleşir ve yayımlanmış gönderileri döndüren yeni bir metot kullanmak daha akıllıca olur. Sonradan başka bir koşul eklediğimizde de (örneğin ileri tarihli gönderileri göstermemek) kodumuzu yalnızca tek bir yerde düzenleriz.

Metodu PostFacade sınıfına koyacak ve ona getPublicArticles() adını vereceğiz.

Gönderilerimizi üstlenecek PostFacade model sınıfımızı app/Model/ dizininde oluşturacağız:

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

Sınıfta, veritabanı Explorer nesnesini yapıcı üzerinden isteriz. Bu, DI container'ın gücünden yararlanır.

HomePresenter sınıfına geçeceğiz; onu, Nette\Database\Explorer bağımlılığından kurtulup yerine yeni sınıfımıza yeni bir bağımlılık koyarak değiştireceğiz.

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

use bölümünde App\Model\PostFacade var, dolayısıyla PHP kodundaki yazımı PostFacade olarak kısaltabiliriz. Bu nesneyi yapıcıda ister, $facade özelliğine yazar ve renderDefault metodunda kullanırız.

Son adım, DI container'a bu nesneyi üretmeyi öğretmektir. Bu genellikle, config/services.neon dosyasının services bölümüne tam sınıf adını ve yapıcı parametrelerini belirten bir öğe eklenerek yapılır. Bu, onu kaydeder ve nesneye o zaman servis denir. Autowiring sihri sayesinde yapıcı parametrelerini genellikle belirtmemize gerek kalmaz; çünkü DI onları tanır ve otomatik aktarır. Böylece yalnızca sınıf adını vermek yeterli olurdu:

...

services:
	- App\Model\PostFacade

Ancak bu satırı da eklemenize gerek yok. services.neon dosyasının search bölümünde, -Facade ya da -Factory ile biten tüm sınıfların DI tarafından otomatik bulunacağı tanımlıdır; PostFacade da bu duruma girer.

Özet

PostFacade sınıfı yapıcısında Nette\Database\Explorer ister ve bu sınıf DI container'da kayıtlı olduğundan, container bu örneği oluşturup aktarır. DI böylece bizim için bir PostFacade örneği oluşturur ve onu isteyen HomePresenter sınıfına yapıcıda aktarır. Matruşka bebeği gibi. :) Herkes yalnızca ne istediğini söyler ve onun nerede ya da nasıl oluşturulduğuyla ilgilenmez. Oluşturmayı DI container üstlenir.

Bağımlılık enjeksiyonu ve yapılandırma hakkında daha fazlasını burada okuyabilirsiniz.