Página con la entrada
Ahora crearemos otra página del blog que mostrará una entrada específica.
Necesitamos crear un nuevo método de renderizado que obtenga un artículo específico y lo pase a la plantilla. Tener este
método en HomePresenter
no es muy elegante, porque estamos hablando de un artículo y no de la página de inicio.
Por lo tanto, creemos PostPresenter
en app/Presentation/Post/
. Este presentador también necesita
conectarse a la base de datos, por lo que aquí nuevamente escribiremos un constructor que requerirá una conexión a la base
de datos.
PostPresenter
podría verse así:
<?php
namespace App\Presentation\Post;
use Nette;
use Nette\Application\UI\Form;
final class PostPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private Nette\Database\Explorer $database,
) {
}
public function renderShow(int $id): void
{
$this->template->post = $this->database
->table('posts')
->get($id);
}
}
No debemos olvidar indicar el namespace correcto App\Presentation\Post
, que está sujeto a la configuración del
mapeo de presentadores.
El método renderShow
requiere un argumento: el ID de un artículo específico que debe mostrarse. Luego, carga
este artículo de la base de datos y lo pasa a la plantilla.
En la plantilla Home/default.latte
insertamos un enlace a la acción Post:show
.
...
<h2><a href="{link Post:show $post->id}">{$post->title}</a></h2>
...
La etiqueta {link}
genera una dirección URL que apunta a la acción Post:show
. También pasa el ID
de la entrada como argumento.
Podemos escribir lo mismo de forma abreviada usando un n:atributo:
...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...
El atributo n:href
es análogo a la etiqueta {link}
.
Sin embargo, para la acción Post:show
aún no existe una plantilla. Podemos intentar abrir el enlace a esta
entrada. Tracy mostrará un error porque la plantilla Post/show.latte
aún
no existe. Si ves otro mensaje de error, probablemente necesitarás habilitar mod_rewrite
en el servidor web.
Por lo tanto, creamos la plantilla Post/show.latte
con este contenido:
{block content}
<p><a n:href="Home:default">← volver a la lista de entradas</a></p>
<div class="date">{$post->created_at|date:'F j, Y'}</div>
<h1 n:block="title">{$post->title}</h1>
<div class="post">{$post->content}</div>
Ahora repasemos las partes individuales de la plantilla.
La primera línea comienza la definición de un bloque llamado “content”, igual que en la página de inicio. Este bloque se
mostrará nuevamente en la plantilla principal. Como puedes ver, falta la etiqueta de cierre {/block}
. Es
opcional.
En la siguiente línea hay un enlace de vuelta a la lista de artículos del blog, para que el usuario pueda moverse fácilmente
entre la lista de artículos y uno específico. Como usamos el atributo n:href
, Nette se encarga automáticamente de
generar los enlaces. El enlace apunta a la acción default
del presentador Home
(también podemos
escribir n:href="Home:"
, porque la acción llamada default
puede omitirse, se completa
automáticamente).
La tercera línea formatea la visualización de la fecha usando un filtro que ya conocemos.
La cuarta línea muestra el título del blog en la etiqueta HTML <h1>
. Esta etiqueta contiene un
atributo que quizás no conozcas (n:block="title"
). ¿Adivinas qué hace? Si leíste la parte anterior con atención,
ya sabes que se trata de un n:atributo
. Este es otro ejemplo de ellos, que es equivalente a:
{block title}<h1>{$post->title}</h1>{/block}
En pocas palabras, este bloque redefine el bloque llamado title
. Este bloque ya está definido en la plantilla
principal layout (/app/Presentation/@layout.latte:11
) y, al igual que con la sobrescritura de métodos en OOP,
este bloque en la plantilla principal se sobrescribe exactamente igual. Así que el <title>
de la página ahora
contiene el título de la entrada mostrada y solo necesitamos usar un simple atributo n:block="title"
. Genial,
¿verdad?
La quinta y última línea de la plantilla muestra todo el contenido de una entrada específica.
Comprobación del ID de la entrada
¿Qué sucede si alguien cambia el ID en la URL e inserta un id
inexistente? Deberíamos ofrecer al usuario un
error agradable del tipo “página no encontrada”. Modificaremos un poco el método de renderizado en
PostPresenter
:
public function renderShow(int $id): void
{
$post = $this->database
->table('posts')
->get($id);
if (!$post) {
$this->error('Página no encontrada');
}
$this->template->post = $post;
}
Si no se puede encontrar la entrada, al llamar a $this->error(...)
mostraremos una página de error 404 con un
mensaje comprensible. Ten en cuenta que en el modo de desarrollo (localhost) no verás esta página de error. En su lugar, se
mostrará Tracy con detalles sobre la excepción, lo cual es bastante conveniente para el desarrollo. Si queremos que se muestren
ambos modos, simplemente cambia el argumento del método setDebugMode
en el archivo Bootstrap.php
.
Resumen
Tenemos una base de datos con entradas y una aplicación web que tiene dos vistas: la primera muestra un resumen de todas las entradas y la segunda muestra una entrada específica.