Página de un artículo
Añadamos a nuestro blog otra página, que mostrará el contenido de un artículo concreto.
Tenemos que crear un nuevo método render que obtenga un artículo concreto y se lo pase a la plantilla. Poner ese método en
HomePresenter no queda muy limpio, porque trata de un solo artículo, no de la portada. Así que creemos una clase
nueva PostPresenter y coloquémosla en app/Presentation/Post/. Este presenter necesitará también una
conexión a la base de datos, así que añadiremos el constructor que exigirá la conexión.
El PostPresenter podría tener este aspecto:
<?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 olvidarnos de indicar el espacio de nombres correcto App\Presentation\Post, que depende de la
configuración del mapeo de
presenters.
El método renderShow requiere un argumento: el ID del artículo que hay que mostrar. Después carga el artículo
de la base de datos y se lo pasa a la plantilla.
En la plantilla Home/default.latte añadimos 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
del artículo como argumento.
Lo mismo se puede escribir de forma concisa con un n:atributo:
...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...
El atributo n:href es parecido a la etiqueta {link}.
La plantilla para la acción Post:show, sin embargo, todavía no existe. Podemos probar a abrir el enlace a ese
artículo. Tracy mostrará un error, porque la plantilla Post/show.latte
todavía no existe. Si ve otro mensaje de error, probablemente tenga que activar mod_rewrite en su servidor web.
Así que crearemos Post/show.latte con este contenido:
{block content}
<p><a n:href="Home:default">← back to posts list</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>
Repasemos ahora las distintas partes de la plantilla.
La primera línea empieza la definición de un bloque llamado “content”, igual que en la portada. Este bloque se mostrará
de nuevo dentro de la plantilla principal del layout. Como ve, falta la etiqueta de cierre {/block}. Es opcional.
La segunda línea ofrece un enlace de vuelta a la lista de artículos del blog, lo que permite al usuario navegar con facilidad
entre la lista y un artículo concreto. Usamos de nuevo el atributo n:href, así que Nette se ocupará de generar la
URL. El enlace apunta a la acción default del presenter Home (también podría escribir
n:href="Home:", porque el nombre de la acción default se puede omitir; se añadirá
automáticamente).
La tercera línea formatea la fecha con un filtro que ya conocemos.
La cuarta línea muestra el título del artículo del blog dentro de una etiqueta HTML <h1>. Esta
etiqueta contiene un atributo que quizá no reconozca (n:block="title"). ¿Adivina qué hace? Si ha leído con
atención la sección anterior, ya sabe que es un n:atributo. Es otro ejemplo, equivalente a:
{block title}<h1>{$post->title}</h1>{/block}
Dicho de forma simple, este bloque redefine el bloque llamado title. Ese bloque ya está definido en la plantilla
principal del layout (/app/Presentation/@layout.latte:11) y, igual que al sobrescribir un método en la POO,
este bloque sobrescribe el de la plantilla principal. Por eso el <title> de la página contendrá ahora el
título del artículo mostrado, y todo lo que hizo falta fue este sencillo atributo n:block="title". Genial,
¿verdad?
La quinta y última línea de la plantilla muestra el contenido completo del artículo concreto.
Comprobar el ID del artículo
¿Qué pasa si alguien cambia el ID de la URL y pone un id que no existe? Deberíamos mostrarle al usuario un
bonito error de “página no encontrada”. Modifiquemos ligeramente el método render de PostPresenter:
public function renderShow(int $id): void
{
$post = $this->database
->table('posts')
->get($id);
if (!$post) {
$this->error('Post not found');
}
$this->template->post = $post;
}
Si el artículo no se puede encontrar, llamar a $this->error(...) mostrará una página 404 con un mensaje
comprensible. Tenga en cuenta que en el entorno de desarrollo (en localhost) no verá esa página de error. En su lugar, Tracy
mostrará la excepción con todos los detalles, lo que resulta bastante cómodo durante el desarrollo. Si quiere probar ambos
modos, basta con cambiar el argumento que se le pasa al método setDebugMode en Bootstrap.php.
Resumen
Tenemos una base de datos con artículos y una aplicación web con dos vistas: la primera muestra un resumen de todos los artículos y la segunda muestra un artículo concreto.