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.