Nette Documentation Preview

syntax
Página única de postagem
************************

.[perex]
Vamos adicionar outra página ao nosso blog, que exibirá o conteúdo de um determinado post do blog.


Precisamos criar um novo método de renderização, que irá buscar um post específico no blog e passá-lo para o modelo. Ter esta visão em `HomePresenter` não é legal porque se trata de um post de blog, não da página inicial. Então, vamos criar uma nova classe `PostPresenter` e colocá-la em `app/UI/Post/`. Ela precisará de uma conexão de banco de dados, então coloque o código *injeção de banco de dados* lá novamente.

O `PostPresenter` deve se parecer com isto:

```php .{file:app/UI/Post/PostPresenter.php}
<?php
namespace App\UI\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);
	}
}
```

Temos que definir um namespaces correto `App\UI\Post` para nosso apresentador. Isso depende do [mapeamento do apresentador |https://github.com/nette-examples/quickstart/blob/v4.0/config/common.neon#L6-L7].

O método `renderShow` requer um argumento - a identificação do posto a ser exibido. Em seguida, ele carrega o posto do banco de dados e passa o resultado para o modelo.

No modelo `Home/default.latte`, adicionamos um link para a ação `Post:show`:

```latte .{file:app/UI/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`. Esta tag também encaminha a identificação do correio como argumento.


O mesmo podemos escrever em breve usando n:attribute:

```latte .{file:app/UI/Home/default.latte}
...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...
```

O atributo `n:href` é similar à tag `{link}`.



O modelo para a ação `Post:show` ainda não existe. Podemos abrir um link para este post. [Tracy |tracy:] mostrará um erro, porque `Post/show.latte` ainda não existe. Se você vir qualquer outro relatório de erro, provavelmente terá que ligar o mod_rewrite em seu servidor web.

Por isso, criaremos `Post/show.latte` com este conteúdo:

```latte .{file:app/UI/Post/show.latte}
{block content}

<p><a n:href="Home:default">← back to posts list</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>
```

Vamos dar uma olhada nas partes individuais.

A primeira linha inicia a definição de um bloco *nomeado* chamado "conteúdo", que vimos anteriormente. Ele será exibido em um modelo de *layout*. Como você pode ver, a etiqueta final `{/block}` está faltando. Ela é opcional.

A segunda linha fornece um backlink para a lista de postagens do blog, para que o usuário possa navegar suavemente para frente e para trás em nosso blog. Usamos novamente o atributo `n:href`, portanto a Nette se encarregará de gerar a URL para nós. O link aponta para a ação `default` do apresentador `Home` (você também poderia escrever `n:href="Home:"`, pois a ação `default` pode ser omitida).

A terceira linha formata o carimbo de tempo de publicação com um filtro, como já sabemos.

A quarta linha exibe o *título* do post do blog como um `<h1>` título. Há uma parte que você pode não estar familiarizado, e que é `n:block="title"`. Você pode adivinhar o que ela faz? Se você leu cuidadosamente as partes anteriores, mencionamos `n: attributes`. Este é outro exemplo. É equivalente a:

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

Em palavras simples, ele *redefine* um bloco chamado `title`. O bloco é definido no modelo *layout* (`/app/UI/@layout.latte:11`) e, como no OOP, ele é anulado aqui. Portanto, a página é `<title>` conterá o título do post exibido. Anulamos o título da página e tudo o que precisávamos era `n:block="title"`. Ótimo, não é?

A quinta e última linha do modelo exibe o conteúdo completo do seu post.


Verificação da identificação do posto .[#toc-checking-post-id]
==============================================================

O que acontece se alguém altera a URL e insere `id` que não existe? Devemos fornecer ao usuário um bom erro de "página não encontrada". Vamos atualizar o método de renderização em `PostPresenter`:

```php .{file:app/UI/Post/PostPresenter.php}
public function renderShow(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);
	if (!$post) {
		$this->error('Post not found');
	}

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

Se o correio não puder ser encontrado, ligando para `$this->error(...)`, aparecerá uma página 404 com uma mensagem agradável e compreensível. Note que em seu ambiente de desenvolvimento (em seu laptop), você não verá a página de erro. Em vez disso, Tracy mostrará a exceção com todos os detalhes, o que é bastante conveniente para o desenvolvimento. Você pode verificar os dois modos, basta alterar o valor passado para `setDebugMode` em `Bootstrap.php`.


Sumário .[#toc-summary]
=======================

Temos um banco de dados com posts em blogs e um aplicativo web com duas visualizações - o primeiro exibe o resumo de todos os posts recentes e o segundo exibe um post específico.

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

Página única de postagem

Vamos adicionar outra página ao nosso blog, que exibirá o conteúdo de um determinado post do blog.

Precisamos criar um novo método de renderização, que irá buscar um post específico no blog e passá-lo para o modelo. Ter esta visão em HomePresenter não é legal porque se trata de um post de blog, não da página inicial. Então, vamos criar uma nova classe PostPresenter e colocá-la em app/UI/Post/. Ela precisará de uma conexão de banco de dados, então coloque o código injeção de banco de dados lá novamente.

O PostPresenter deve se parecer com isto:

<?php
namespace App\UI\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);
	}
}

Temos que definir um namespaces correto App\UI\Post para nosso apresentador. Isso depende do mapeamento do apresentador.

O método renderShow requer um argumento – a identificação do posto a ser exibido. Em seguida, ele carrega o posto do banco de dados e passa o resultado para o modelo.

No modelo Home/default.latte, adicionamos 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. Esta tag também encaminha a identificação do correio como argumento.

O mesmo podemos escrever em breve usando n:attribute:

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

O atributo n:href é similar à tag {link}.

O modelo para a ação Post:show ainda não existe. Podemos abrir um link para este post. Tracy mostrará um erro, porque Post/show.latte ainda não existe. Se você vir qualquer outro relatório de erro, provavelmente terá que ligar o mod_rewrite em seu servidor web.

Por isso, criaremos Post/show.latte com este conteúdo:

{block content}

<p><a n:href="Home:default">← back to posts list</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>

Vamos dar uma olhada nas partes individuais.

A primeira linha inicia a definição de um bloco nomeado chamado „conteúdo“, que vimos anteriormente. Ele será exibido em um modelo de layout. Como você pode ver, a etiqueta final {/block} está faltando. Ela é opcional.

A segunda linha fornece um backlink para a lista de postagens do blog, para que o usuário possa navegar suavemente para frente e para trás em nosso blog. Usamos novamente o atributo n:href, portanto a Nette se encarregará de gerar a URL para nós. O link aponta para a ação default do apresentador Home (você também poderia escrever n:href="Home:", pois a ação default pode ser omitida).

A terceira linha formata o carimbo de tempo de publicação com um filtro, como já sabemos.

A quarta linha exibe o título do post do blog como um <h1> título. Há uma parte que você pode não estar familiarizado, e que é n:block="title". Você pode adivinhar o que ela faz? Se você leu cuidadosamente as partes anteriores, mencionamos n: attributes. Este é outro exemplo. É equivalente a:

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

Em palavras simples, ele redefine um bloco chamado title. O bloco é definido no modelo layout (/app/UI/@layout.latte:11) e, como no OOP, ele é anulado aqui. Portanto, a página é <title> conterá o título do post exibido. Anulamos o título da página e tudo o que precisávamos era n:block="title". Ótimo, não é?

A quinta e última linha do modelo exibe o conteúdo completo do seu post.

Verificação da identificação do posto

O que acontece se alguém altera a URL e insere id que não existe? Devemos fornecer ao usuário um bom erro de „página não encontrada“. Vamos atualizar o método de renderização em PostPresenter:

public function renderShow(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);
	if (!$post) {
		$this->error('Post not found');
	}

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

Se o correio não puder ser encontrado, ligando para $this->error(...), aparecerá uma página 404 com uma mensagem agradável e compreensível. Note que em seu ambiente de desenvolvimento (em seu laptop), você não verá a página de erro. Em vez disso, Tracy mostrará a exceção com todos os detalhes, o que é bastante conveniente para o desenvolvimento. Você pode verificar os dois modos, basta alterar o valor passado para setDebugMode em Bootstrap.php.

Sumário

Temos um banco de dados com posts em blogs e um aplicativo web com duas visualizações – o primeiro exibe o resumo de todos os posts recentes e o segundo exibe um post específico.