Page d'un article
Ajoutons à notre blog une autre page, qui affichera le contenu d'un article précis.
Nous devons créer une nouvelle méthode render qui récupérera un article précis et le passera au template. Placer cette
méthode dans HomePresenter n'est pas très propre, car il s'agit d'un article isolé et non de la page d'accueil.
Créons donc une nouvelle classe PostPresenter et plaçons-la dans app/Presentation/Post/. Ce presenter
aura lui aussi besoin d'une connexion à la base de données, nous ajouterons donc le constructeur qui l'exigera.
Le PostPresenter pourrait ressembler à ceci :
<?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);
}
}
Nous ne devons pas oublier d'indiquer le bon espace de noms App\Presentation\Post, qui dépend de la configuration
du mapping des presenters.
La méthode renderShow exige un argument : l'ID de l'article à afficher. Elle charge ensuite l'article depuis la
base et le passe au template.
Dans le template Home/default.latte, nous ajoutons un lien vers l'action Post:show :
...
<h2><a href="{link Post:show $post->id}">{$post->title}</a></h2>
...
La balise {link} génère une adresse URL pointant vers l'action Post:show. Elle passe aussi l'ID de
l'article en argument.
La même chose peut s'écrire brièvement à l'aide d'un n:attribut :
...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...
L'attribut n:href est semblable à la balise {link}.
Le template de l'action Post:show n'existe cependant pas encore. Nous pouvons essayer d'ouvrir le lien vers cet
article. Tracy affichera une erreur, car le template Post/show.latte
n'existe pas encore. Si vous voyez un autre message d'erreur, vous devez probablement activer mod_rewrite sur votre
serveur web.
Créons donc Post/show.latte avec ce contenu :
{block content}
<p><a n:href="Home:default">← retour à la liste des articles</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>
Passons maintenant en revue les différentes parties du template.
La première ligne commence la définition d'un bloc nommé “content”, comme sur la page d'accueil. Ce bloc sera de nouveau
affiché dans le template de layout principal. Comme vous le voyez, la balise fermante {/block} manque. Elle est
facultative.
La deuxième ligne fournit un lien de retour vers la liste des articles du blog, ce qui permet à l'utilisateur de naviguer
facilement entre la liste et un article précis. Nous utilisons de nouveau l'attribut n:href, Nette se chargera donc
de générer l'URL. Le lien pointe vers l'action default du presenter Home (vous pourriez aussi écrire
n:href="Home:", car le nom d'action default peut être omis, il sera ajouté automatiquement).
La troisième ligne met en forme la date à l'aide d'un filtre que nous connaissons déjà.
La quatrième ligne affiche le titre de l'article dans une balise HTML <h1>. Cette balise contient un
attribut que vous ne connaissez peut-être pas (n:block="title"). Devinez-vous ce qu'il fait ? Si vous avez lu
attentivement la section précédente, vous savez déjà que c'est un n:attribut. En voici un autre exemple,
équivalent à :
{block title}<h1>{$post->title}</h1>{/block}
Dit simplement, ce bloc redéfinit le bloc nommé title. Ce bloc est déjà défini dans le template principal du
layout (/app/Presentation/@layout.latte:11) et, tout comme la redéfinition d'une méthode en POO, ce bloc
remplace celui du template principal. Le <title> de la page contiendra donc désormais le titre de l'article
affiché, et il n'a suffi pour cela que de ce simple attribut n:block="title". Génial, non ?
La cinquième et dernière ligne du template affiche le contenu complet de l'article.
Vérifier l'ID de l'article
Que se passe-t-il si quelqu'un modifie l'ID dans l'URL et y met un id inexistant ? Nous devrions montrer à
l'utilisateur une jolie erreur “page non trouvée”. Modifions légèrement la méthode render de
PostPresenter :
public function renderShow(int $id): void
{
$post = $this->database
->table('posts')
->get($id);
if (!$post) {
$this->error('Article non trouvé');
}
$this->template->post = $post;
}
Si l'article est introuvable, l'appel à $this->error(...) affichera une page 404 avec un message
compréhensible. Notez qu'en environnement de développement (sur localhost), vous ne verrez pas cette page d'erreur. Tracy
affichera à la place l'exception avec tous les détails, ce qui est bien pratique pour le développement. Si vous voulez tester
les deux modes, changez simplement l'argument passé à la méthode setDebugMode dans Bootstrap.php.
Résumé
Nous avons une base de données contenant des articles et une application web avec deux vues : la première affiche un aperçu de tous les articles, la seconde un article précis.