Model

Uygulama büyüdükçe, yakında farklı yerlerde, farklı presenter'larda, veritabanıyla benzer işlemler yapmamız gerektiğini fark edeceğiz. Örneğin, en son yayınlanan makaleleri almak. Uygulamayı, örneğin makalelere taslak olup olmadıklarını belirten bir bayrak ekleyerek geliştirirsek, o zaman uygulamada makalelerin veritabanından alındığı tüm yerleri gözden geçirmeli ve yalnızca taslak olmayan makalelerin seçilmesi için where koşulunu eklemeliyiz.

Bu noktada, veritabanıyla doğrudan çalışmak yetersiz hale gelir ve bize yayınlanmış makaleleri döndürecek yeni bir fonksiyonla yardım etmek daha akıllıca olacaktır. Ve daha sonra başka bir koşul eklediğimizde, örneğin gelecekteki bir tarihe sahip makalelerin gösterilmemesi gerektiğini, kodu yalnızca tek bir yerde düzenleriz.

Fonksiyonu örneğin PostFacade sınıfına yerleştireceğiz ve getPublicArticles() olarak adlandıracağız.

app/Model/ dizininde, makalelerimizle ilgilenecek olan model sınıfımız PostFacade'i 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, yapıcı aracılığıyla veritabanı Explorer'ı aktarmasını isteyeceğiz. Böylece DI konteynerinin gücünden yararlanacağız.

HomePresenter'a geçeceğiz, onu Nette\Database\Explorer bağımlılığından kurtulacak ve yeni sınıfımıza olan yeni bağımlılıkla değiştirecek şekilde düzenleyeceğ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, bu yüzden PHP kodundaki yazımı PostFacade olarak kısaltabiliriz. Bu nesneyi yapıcıda isteyeceğiz, $facade özelliğine yazacağız ve renderDefault metodunda kullanacağız.

Geriye kalan son adım, DI konteynerine bu nesneyi nasıl üreteceğini öğretmektir. Bu genellikle config/services.neon dosyasındaki services bölümüne bir madde işareti ekleyerek, sınıfın tam adını ve yapıcı parametrelerini belirterek yapılır. Böylece onu kaydederiz ve nesne daha sonra servis olarak adlandırılır. Autowiring adlı sihir sayesinde, çoğu zaman yapıcı parametrelerini belirtmemiz gerekmez, çünkü DI onları kendi başına tanır ve aktarır. Bu nedenle yalnızca sınıfın adını belirtmek yeterli olacaktır:

...

services:
	- App\Model\PostFacade

Ancak, bu satırı eklemeniz bile gerekmez. services.neon başındaki search bölümünde, -Facade veya -Factory ile biten tüm sınıfların DI tarafından kendi kendine bulunacağı tanımlanmıştır, bu da PostFacade durumu için geçerlidir.

Özet

PostFacade sınıfı, yapıcıda Nette\Database\Explorer'ın aktarılmasını ister ve bu sınıf DI konteynerinde kayıtlı olduğundan, konteyner bu örneği oluşturur ve aktarır. DI bizim için PostFacade örneğini bu şekilde oluşturur ve onu isteyen HomePresenter sınıfının yapıcısına aktarır. Böyle bir matruşka. :) Herkes sadece ne istediğini söyler ve neyin nerede ve nasıl yaratıldığıyla ilgilenmez. Oluşturma işini DI konteyneri halleder.

Burada dependency injection ve yapılandırma hakkında daha fazla bilgi edinebilirsiniz.