Comentários
O blog foi implantado, escrevemos alguns posts muito bons no blog e os publicamos via Adminer. As pessoas estão lendo o blog e são muito apaixonadas por nossas idéias. Estamos recebendo muitos e-mails com elogios a cada dia. Mas para que servem todos os elogios quando os recebemos apenas no e-mail, para que ninguém mais possa lê-lo? Não seria melhor se as pessoas pudessem comentar diretamente no blog para que todos pudessem ler o quanto somos fantásticos?
Vamos tornar todos os artigos louváveis.
Criando uma nova tabela
Ligue novamente o Adminer e crie uma nova tabela chamada comments
com estas colunas:
id
int, verificar autoincremento (AI)post_id
, uma chave estrangeira que faz referência à tabelaposts
name
varchar, comprimento 255email
varchar, comprimento 255content
textocreated_at
timestamp
Deveria ser assim:
Não se esqueça de usar o armazenamento de mesa InnoDB e pressione Save.
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;
Formulário para comentar
Primeiro, precisamos criar um formulário, que permitirá aos usuários comentar em nossa página. Nette Framework tem um ótimo suporte para formulários. Eles podem ser configurados em um apresentador e renderizados em um modelo.
Nette Framework tem um conceito de componentes. Um **componente*** é uma classe ou código reutilizável, que pode ser
anexado a outro componente. Até mesmo um apresentador é um componente. Cada componente é criado usando a fábrica de
componentes. Portanto, vamos definir os comentários da fábrica em PostPresenter
.
protected function createComponentCommentForm(): Form
{
$form = new Form; // means 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;
}
Vamos explicar um pouco. A primeira linha cria uma nova instância do componente Form
. Os seguintes métodos
estão anexando entradas HTML na definição do formulário. ->addText
renderizará como
<input type=text name=name>
, com <label>Your name:</label>
. Como você já deve ter
adivinhado neste momento, o ->addTextArea
anexa um <textarea>
e ->addSubmit
acrescenta um <input type=submit>
. Há mais métodos como esse, mas isso é tudo que você tem que saber agora
mesmo. Você pode saber mais na documentação.
Uma vez que o componente do formulário é definido em um apresentador, podemos renderizá-lo (exibir) em um modelo. Para
isso, coloque a tag {control}
no final do modelo de detalhe do post, em Post/show.latte
. Como o nome do
componente é commentForm
(é derivado do nome do método createComponentCommentForm
), a tag terá
o seguinte aspecto
...
<h2>Post new comment</h2>
{control commentForm}
Agora, se você verificar os detalhes de algum post, haverá um novo formulário para postar comentários.
Salvando para o banco de dados
Você já tentou enviar alguns dados? Você deve ter notado, que o formulário não está realizando nenhuma ação. Só que está lá, com um visual legal e sem fazer nada. Temos que anexar-lhe um método de retorno, que salvará os dados enviados.
Coloque a seguinte linha antes da linha return
na fábrica de componentes para o commentForm
:
$form->onSuccess[] = $this->commentFormSucceeded(...);
Significa „depois que o formulário for enviado com sucesso, ligue para o método commentFormSucceeded
do
atual apresentador“. Este método ainda não existe, portanto, vamos criá-lo.
private function commentFormSucceeded(\stdClass $data): void
{
$id = $this->getParameter('id');
$this->database->table('comments')->insert([
'post_id' => $id,
'name' => $data->name,
'email' => $data->email,
'content' => $data->content,
]);
$this->flashMessage('Thank you for your comment', 'success');
$this->redirect('this');
}
Você deve colocá-lo logo após a fábrica de componentes commentForm
.
O novo método tem um argumento que é a instância do formulário que está sendo apresentado, criado pela fábrica de
componentes. Recebemos os valores enviados em $data
. E depois inserimos os dados na tabela do banco de dados
comments
.
Há mais duas chamadas de método para explicar. O redirecionamento é literalmente redirecionado para a página atual. Você
deve fazer isso toda vez que o formulário for apresentado, válido, e a operação de retorno da chamada fez o que deveria ter
feito. Além disso, quando você redireciona a página após enviar o formulário, você não verá a conhecida mensagem
Would you like to submit the post data again?
que às vezes você pode ver no navegador. (Em geral, após submeter um
formulário pelo método POST
, você deve sempre redirecionar o usuário para uma ação GET
).
O flashMessage
é para informar o usuário sobre o resultado de alguma operação. Como estamos redirecionando,
a mensagem não pode ser passada diretamente para o modelo e entregue. Portanto, existe este método, que irá armazená-lo e
torná-lo disponível no carregamento da próxima página. As mensagens flash são renderizadas no arquivo padrão
app/UI/@layout.latte
, e é assim que parece:
<div n:foreach="$flashes as $flash" n:class="flash, $flash->type">
{$flash->message}
</div>
Como já sabemos, eles são passados automaticamente para o modelo, de modo que não é preciso pensar muito sobre isso, ele apenas funciona. Para obter mais detalhes, consulte a documentação.
Comentários
Esta é uma das coisas que você vai adorar. O Nette Database tem este recurso legal chamado Explorer. Você se lembra que nós criamos as tabelas como InnoDB? Adminer criou as chamadas chaves estrangeiras que nos pouparão uma tonelada de trabalho.
O Nette Database Explorer utiliza as chaves estrangeiras para resolver as relações entre tabelas, e conhecendo as relações, ele pode criar automaticamente consultas para você.
Como você deve se lembrar, passamos a variável $post
para o modelo em PostPresenter::renderShow()
e agora queremos iterar através de todos os comentários que têm a coluna post_id
igual ao nosso
$post->id
. Você pode fazer isso ligando para $post->related('comments')
. É muito simples. Veja
o código resultante.
public function renderShow(int $id): void
{
...
$this->template->post = $post;
$this->template->comments = $post->related('comments')->order('created_at');
}
E o modelo:
...
<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>
...
Observe o atributo especial n:tag-if
. Você já sabe como funciona n: attributes
. Bem, se você
preender o atributo com tag-
, ele só envolverá as tags, não o seu conteúdo. Isto permite que você transforme
o nome do comentarista em um link, caso ele tenha fornecido seu e-mail. Estas duas linhas são idênticas em resultados:
<strong n:tag-if="$important"> Hello there! </strong>
{if $important}<strong>{/if} Hello there! {if $important}</strong>{/if}