Nette Documentation Preview

syntax
Página com a postagem
*********************

.[perex]
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 .{file:app/Presentation/Post/PostPresenter.php}
<?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 |https://github.com/nette-examples/quickstart/blob/v4.0/config/common.neon#L6-L7].

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`.

```latte .{file:app/Presentation/Home/default.latte}
...
<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:

```latte .{file:app/Presentation/Home/default.latte}
...
<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 |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:

```latte .{file:app/Presentation/Post/show.latte}
{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:

```latte
{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`:

```php .{file:app/Presentation/Post/PostPresenter.php}
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.

{{priority: -1}}
{{sitename: Nette Quickstart}}

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.