Modelo

A medida que nuestra aplicación crece, pronto descubrimos que necesitamos realizar operaciones de base de datos similares en varias ubicaciones y en varios presentadores, por ejemplo, adquirir los artículos publicados más recientes. Si mejoramos nuestra aplicación añadiendo una bandera a los artículos para indicar un estado de trabajo en curso, también debemos recorrer todas las ubicaciones de nuestra aplicación y añadir una cláusula where para asegurarnos de que sólo se seleccionan los artículos terminados.

En este punto, el trabajo directo con la base de datos resulta insuficiente y será más inteligente ayudarnos con una nueva función que devuelva los artículos publicados. Y cuando añadamos otra cláusula más adelante (por ejemplo para no mostrar artículos con fecha futura), sólo editaremos nuestro código en un lugar.

Colocaremos la función en la clase PostFacade y la llamaremos getPublicArticles().

Crearemos nuestra clase modelo PostFacade en el directorio app/Model/ para que se encargue de nuestros artículos:

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

En la clase pasaremos la base de datos Explorer. Esto aprovechará la potencia del contenedor DI.

Pasaremos a HomePresenter que editaremos de forma que nos deshagamos de la dependencia de Nette\Database\Explorer sustituyéndola por una nueva dependencia de nuestra nueva clase.

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

En la sección de uso, estamos usando App\Model\PostFacade, por lo que podemos acortar el código PHP a PostFacade. Solicitamos este objeto en el constructor, lo escribimos en la propiedad $facade y lo usamos en el método renderDefault.

El último paso que queda es enseñar al contenedor DI a producir este objeto. Esto se hace normalmente añadiendo una viñeta al archivo config/services.neon en la sección services, dando el nombre completo de la clase y los parámetros del constructor. Esto lo registra, por así decirlo, y el objeto se llama entonces service. Gracias a una magia llamada autocableado, normalmente no necesitamos especificar los parámetros del constructor porque DI los reconocerá y los pasará automáticamente. Por lo tanto, bastaría con proporcionar el nombre de la clase:

...

services:
	- App\Model\PostFacade

Sin embargo, tampoco es necesario añadir esta línea. En la sección search al principio de services.neon se define que todas las clases que terminen en -Facade o -Factory serán buscadas por DI automáticamente, lo que también es el caso para PostFacade.

Resumen

La clase PostFacade pide Nette\Database\Explorer en un constructor y como esta clase está registrada en el contenedor DI, el contenedor crea esta instancia y la pasa. DI de esta manera nos crea una instancia de PostFacade y se la pasa en un constructor a la clase HomePresenter que la pidió. Una especie de muñeca Matryoshka de código :) Todos los componentes sólo piden lo que necesitan y no les importa dónde y cómo se crea. La creación es manejada por el contenedor DI.

Aquí puedes leer más sobre inyección de dependencias, y sobre configuración.