Commentaires

Le blog a été déployé, nous avons écrit de très bons articles de blog et les avons publiés via Adminer. Les gens lisent le blog et sont très passionnés par nos idées. Nous recevons chaque jour de nombreux courriels élogieux. Mais à quoi servent tous ces éloges si nous ne les recevons que dans le courrier électronique, de sorte que personne d'autre ne peut les lire ? Ne serait-il pas préférable que les gens puissent commenter directement sur le blog afin que tout le monde puisse lire à quel point nous sommes géniaux ?

Rendons tous les articles commentables.

Création d'un nouveau tableau

Lancez à nouveau Adminer et créez une nouvelle table nommée comments avec ces colonnes :

  • id int, vérifier l'auto-incrément (AI)
  • post_id, une clé étrangère qui fait référence à la table posts
  • name varchar, longueur 255
  • email varchar, longueur 255
  • content texte
  • created_at timestamp

Cela devrait ressembler à ceci :

N'oubliez pas d'utiliser le stockage de table InnoDB et cliquez sur Enregistrer.

CREATE TABLE `comments` (
	`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`post_id` int(11) NOT NULL,
	`name` varchar(250) NOT NULL,
	`email` varchar(250) NOT NULL,
	`content` text NOT NULL,
	`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
	FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`)
) ENGINE=InnoDB CHARSET=utf8;

Formulaire de commentaire

Tout d'abord, nous devons créer un formulaire qui permettra aux utilisateurs de commenter notre page. Le Nette Framework offre un support impressionnant pour les formulaires. Ils peuvent être configurés dans un présentateur et rendus dans un modèle.

Nette Framework a un concept de composants. Un composant est une classe réutilisable ou un morceau de code, qui peut être attaché à un autre composant. Même un présentateur est un composant. Chaque composant est créé à l'aide de la fabrique de composants. Définissons donc la fabrique du formulaire de commentaires dans PostPresenter.

protected function createComponentCommentForm(): Form
{
	$form = new Form; // signifie Nette\Application\UI\Form

	$form->addText('name', 'Your name:')
		->setRequired();

	$form->addEmail('email', 'Email:');

	$form->addTextArea('content', 'Comment:')
		->setRequired();

	$form->addSubmit('send', 'Publish comment');

	return $form;
}

Nous allons l'expliquer un peu. La première ligne crée une nouvelle instance du composant Form. Les méthodes suivantes permettent d'attacher des entrées HTML à la définition du formulaire. ->addText sera rendu en tant que <input type=text name=name>, avec <label>Your name:</label>. Comme vous l'avez sans doute déjà deviné, le composant ->addTextArea attache une balise <textarea> et ->addSubmit ajoute un <input type=submit>. Il existe d'autres méthodes de ce type, mais c'est tout ce que vous devez savoir pour le moment. Vous pouvez en apprendre davantage dans la documentation.

Une fois le composant de formulaire défini dans un présentateur, nous pouvons le rendre (l'afficher) dans un modèle. Pour ce faire, placez la balise {control} à la fin du modèle de détail de l'article, dans Post/show.latte. Comme le nom du composant est commentForm (dérivé du nom de la méthode createComponentCommentForm), la balise ressemblera à ceci

...
<h2>Post new comment</h2>

{control commentForm}

Maintenant, si vous consultez les détails d'un article, vous trouverez un nouveau formulaire pour poster des commentaires.

Sauvegarde dans la base de données

Avez-vous essayé de soumettre des données ? Vous avez peut-être remarqué que le formulaire n'effectue aucune action. Il est juste là, à l'air cool et ne fait rien. Nous devons attacher une méthode de rappel à ce formulaire, qui enregistrera les données soumises.

Placez la ligne suivante avant la ligne return dans la fabrique du composant commentForm:

$form->onSuccess[] = $this->commentFormSucceeded(...);

Elle signifie “après que le formulaire ait été soumis avec succès, appelez la méthode commentFormSucceeded du présentateur actuel”. Cette méthode n'existe pas encore, alors créons-la.

private function commentFormSucceeded(\stdClass $data): void
{
	$postId = $this->getParameter('postId');

	$this->database->table('comments')->insert([
		'post_id' => $postId,
		'name' => $data->name,
		'email' => $data->email,
		'content' => $data->content,
	]);

	$this->flashMessage('Thank you for your comment', 'success');
	$this->redirect('this');
}

Vous devez la placer juste après la fabrique du composant commentForm.

La nouvelle méthode a un argument qui est l'instance du formulaire soumis, créé par la fabrique de composants. Nous recevons les valeurs soumises dans $data. Et ensuite nous insérons les données dans la table de la base de données comments.

Il y a deux autres appels de méthode à expliquer. La redirection redirige littéralement vers la page actuelle. Vous devez le faire à chaque fois que le formulaire est soumis, valide et que l'opération de rappel a fait ce qu'elle devait faire. En outre, lorsque vous redirigez la page après avoir soumis le formulaire, vous ne verrez pas le message bien connu Would you like to submit the post data again? que vous pouvez parfois voir dans le navigateur. (En général, après avoir soumis un formulaire par la méthode POST, vous devriez toujours rediriger l'utilisateur vers une action GET ).

Le message flashMessage sert à informer l'utilisateur du résultat d'une opération quelconque. Comme il s'agit d'une redirection, le message ne peut pas être transmis directement au modèle et rendu. Il y a donc cette méthode qui le stocke et le rend disponible au prochain chargement de la page. Les messages flash sont rendus dans le fichier app/UI/@layout.latte par défaut, et cela ressemble à ceci :

<div n:foreach="$flashes as $flash" n:class="flash, $flash->type">
	{$flash->message}
</div>

Comme nous le savons déjà, ils sont transmis automatiquement au modèle, de sorte que vous n'avez pas besoin d'y penser trop, cela fonctionne tout simplement. Pour plus de détails , consultez la documentation.

Rendu des commentaires

Voici l'une des choses que vous allez adorer. La base de données Nette dispose d'une fonctionnalité sympa appelée Explorer. Vous vous souvenez que nous avons créé les tables en InnoDB ? Adminer a créé ce qu'on appelle des clés étrangères qui vont nous épargner une tonne de travail.

Nette Database Explorer utilise les clés étrangères pour résoudre les relations entre les tables, et connaissant les relations, il peut automatiquement créer des requêtes pour vous.

Comme vous vous en souvenez peut-être, nous avons passé la variable $post au modèle dans PostPresenter::renderShow() et maintenant nous voulons itérer à travers tous les commentaires qui ont la colonne post_id égale à notre $post->id. Vous pouvez le faire en appelant $post->related('comments'). C'est aussi simple que cela. Regardez le code résultant.

public function renderShow(int $postId): void
{
	...
	$this->template->post = $post;
	$this->template->comments = $post->related('comments')->order('created_at');
}

Et le modèle :

...
<h2>Comments</h2>

<div class="comments">
	{foreach $comments as $comment}
		<p><b><a href="mailto:{$comment->email}" n:tag-if="$comment->email">
			{$comment->name}
		</a></b> said:</p>

		<div>{$comment->content}</div>
	{/foreach}
</div>
...

Remarquez l'attribut spécial n:tag-if. Vous savez déjà comment fonctionne n: attributes. Si vous faites précéder l'attribut de tag-, il n'enveloppera que les balises, et non leur contenu. Cela vous permet de transformer le nom du commentateur en un lien s'il a fourni son adresse électronique. Les résultats de ces deux lignes sont identiques :

<strong n:tag-if="$important"> Hello there! </strong>

{if $important}<strong>{/if} Hello there! {if $important}</strong>{/if}