Model | First Application

As our application grows, we soon find out that we need to perform similar database operations in various locations and in various presenters, for example acquiring the newest published articles. If we improve our application by adding a flag to articles to indicate a work-in-progress state, we must also go through all locations in our application and add a where clause to make sure only finished articles are selected.

At this point, direct work with the database becomes insufficient and it will be smarter to help ourselves with a new function that returns published articles. And when we add another clause later (for example not to display articles with a future date), we only edit our code in one place.

We'll place the function into the PostFacade class and call it getPublicArticles().

We'll create our model class PostFacade in the directory app/Model/ to take care of our articles. Let's place it into the PostFacade.php file.

namespace App\Model;

use Nette;

final class PostFacade
{
	use Nette\SmartObject;

	private Nette\Database\Explorer $database;

	public function __construct(Nette\Database\Explorer $database)
	{
		$this->database = $database;
	}

	public function getPublicArticles()
	{
		return $this->database
			->table('posts')
			->where('created_at < ', new \DateTime)
			->order('created_at DESC');
	}
}

In the class we pass the database Explorer. This will take advantage of the power of DI container.

Add a line with the full class name to the config/services.neon file in the services section:

services:
	- App\Router\RouterFactory::createRouter
	- App\Model\PostFacade

That way we tell Nette and its DI container the following: “If somebody wants an instance of this class, you know where to find it. Give that instance all it needs and prepare it for being used in other classes.” A class registered in this way is then called a service.

We will switch to HomepagePresenter.php which we will edit so that we get rid of the dependency on Nette\Database\Explorer replacing that with a new dependency on our new class.

namespace App\Presenters;

use App\Model\PostFacade;
use Nette;

final class HomepagePresenter extends Nette\Application\UI\Presenter
{
	private PostFacade $facade;

	public function __construct(PostFacade $facade)
	{
		$this->facade = $facade;
	}

	public function renderDefault(): void
	{
		$this->template->posts = $this->facade
			->getPublicArticles()
			->limit(5);
	}
}

In the use section, we are using App\Model\PostFacade. That way we can shorten our PHP code only to PostFacade (don't be afraid of it, it works even in comments and your clever IDE should be able to handle it)

We request PostFacade in a constructor which we will assign to the $facade attribute and in the renderDefault method we are calling the getPublicArticles() method. We are also calling the limit(5) method on the result of that function.

The PostFacade class asks for Nette\Database\Explorer in a constructor and because this class is registered in the DI container, the container creates this instance and passes it. DI this way creates an PostFacade instance for us and passes it in a constructor to the HomepagePresenter class which asked for it. Sort of a Matryoshka doll of code. :) All the components only request what they need and they don't care where and how it gets created. The creation is handled by DI container.