Página com a postagem

Agora criaremos outra página do blog, que exibirá uma postagem específica.

Precisamos criar um novo método de renderização que obterá um artigo específico e o passará para o template. Ter este método no HomePresenter não é muito elegante, pois estamos falando de um artigo e não da página inicial. Portanto, criaremos um PostPresenter em app/Presentation/Post/. Este presenter também precisa se conectar ao banco de dados, então escreveremos novamente um construtor que exigirá a conexão com o banco de dados.

O PostPresenter poderia, portanto, ter a seguinte aparência:

<?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);
	}
}

Não devemos esquecer de indicar o namespace correto App\Presentation\Post, que está sujeito à configuração de mapeamento de presenters.

O método renderShow requer um argumento – o ID de um artigo específico que deve ser exibido. Em seguida, ele carrega este artigo do banco de dados e o passa para o template.

No template Home/default.latte, inseriremos um link para a ação Post:show.

...
<h2><a href="{link Post:show $post->id}">{$post->title}</a></h2>
...

A tag {link} gera um endereço URL que aponta para a ação Post:show. Também passa o ID da postagem como argumento.

Podemos escrever o mesmo de forma abreviada usando um n:atributo:

...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...

O atributo n:href é análogo à tag {link}.

No entanto, ainda não existe um template para a ação Post:show. Podemos tentar abrir o link para esta postagem. O Tracy exibirá um erro porque o template Post/show.latte ainda não existe. Se você vir outra mensagem de erro, provavelmente precisará habilitar o mod_rewrite no servidor web.

Criaremos, portanto, o template Post/show.latte com este conteúdo:

{block content}

<p><a n:href="Home:default">← voltar para a lista de postagens</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>

Agora vamos percorrer as partes individuais do template.

A primeira linha começa a definição do bloco chamado “content”, assim como na página inicial. Este bloco será novamente exibido no template principal. Como você pode ver, falta a tag final {/block}. Ela é, na verdade, opcional.

Na linha seguinte, há um link de volta para a lista de artigos do blog, para que o usuário possa navegar facilmente entre a lista de artigos e um artigo específico. Como estamos usando o atributo n:href, o Nette cuidará da geração dos links. O link aponta para a ação default do presenter Home (podemos escrever também n:href="Home:", pois a ação chamada default pode ser omitida, ela é completada automaticamente).

A terceira linha formata a exibição da data usando o filtro que já conhecemos.

A quarta linha exibe o título do blog na tag HTML <h1>. Esta tag contém um atributo que talvez você não conheça (n:block="title"). Consegue adivinhar o que ele faz? Se você leu a parte anterior com atenção, já sabe que se trata de um n:atributo. Este é outro exemplo deles, que é equivalente a:

{block title}<h1>{$post->title}</h1>{/block}

Simplificando, este bloco redefine o bloco chamado title. Este bloco já está definido no template principal layout (/app/Presentation/@layout.latte:11) e, assim como na sobreposição de métodos em OOP, este bloco no template principal é sobreposto da mesma forma. Portanto, o <title> da página agora contém o título da postagem exibida, e bastou usar apenas um simples atributo n:block="title". Ótimo, não é?

A quinta e última linha do template exibe todo o conteúdo de uma postagem específica.

Verificação do ID da postagem

O que acontece se alguém alterar o ID na URL e inserir algum id inexistente? Devemos oferecer ao usuário um erro agradável do tipo “página não encontrada”. Modificaremos, portanto, um pouco o método de renderização no PostPresenter:

public function renderShow(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);
	if (!$post) {
		$this->error('Página não encontrada');
	}

	$this->template->post = $post;
}

Se a postagem não puder ser encontrada, chamando $this->error(...) exibiremos uma página de erro 404 com uma mensagem compreensível. Atenção: no modo de desenvolvimento (localhost), você não verá esta página de erro. Em vez disso, o Tracy aparecerá com detalhes sobre a exceção, o que é bastante vantajoso para o desenvolvimento. Se quisermos exibir ambos os modos, basta alterar o argumento do método setDebugMode no arquivo Bootstrap.php.

Resumo

Temos um banco de dados com postagens e uma aplicação web que tem duas views – a primeira exibe uma visão geral de todas as postagens e a segunda exibe uma postagem específica.