Nette Documentation Preview

syntax
Página individual
*****************

.[perex]
Vamos a añadir otra página a nuestro blog, que mostrará el contenido de una entrada del blog en particular.


Necesitamos crear un nuevo método de renderizado, que obtendrá una entrada de blog específica y la pasará a la plantilla. Tener esta vista en `HomePresenter` no es agradable porque se trata de una entrada de blog, no de la página principal. Por lo tanto, vamos a crear una nueva clase `PostPresenter` y colocarla en `app/UI/Post/`. Necesitará una conexión a la base de datos, por lo que pondremos el código de *inyección a la base de datos* allí de nuevo.

El `PostPresenter` debería verse así:

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

Tenemos que establecer un namespaces correcto `App\UI\Post` para nuestro presentador. Depende de la [asignación del |https://github.com/nette-examples/quickstart/blob/v4.0/config/common.neon#L6-L7] presentador.

El método `renderShow` requiere un argumento - el ID de la entrada a mostrar. Luego, carga la entrada desde la base de datos y pasa el resultado a la plantilla.

En la plantilla `Home/default.latte` añadimos un enlace a la acción `Post:show`:

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

La etiqueta `{link}` genera una dirección URL que apunta a la acción `Post:show`. Esta etiqueta también reenvía el ID del post como argumento.


Lo mismo podemos escribir en breve utilizando n:attribute:

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

El atributo `n:href` es similar a la etiqueta `{link}`.



La plantilla para la acción `Post:show` aún no existe. Podemos abrir un enlace a este post. [Tracy |tracy:] mostrará un error, por qué `Post/show.latte` no existe. Si usted ve cualquier otro informe de error que probablemente tiene que activar mod_rewrite en su servidor web.

Así que vamos a crear `Post/show.latte` con este contenido:

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

Echemos un vistazo a las partes individuales.

La primera línea inicia la definición de un *bloque con nombre* llamado "contenido" que vimos antes. Se mostrará en una *plantilla de diseño*. Como puedes ver, falta la etiqueta final `{/block}`. Es opcional.

La segunda línea proporciona un backlink a la lista de entradas del blog, para que el usuario pueda navegar sin problemas hacia adelante y hacia atrás en nuestro blog. Volvemos a utilizar el atributo `n:href`, por lo que Nette se encargará de generar la URL por nosotros. El enlace apunta a la acción `default` del presentador `Home` (también se podría escribir `n:href="Home:"`, ya que la acción `default` se puede omitir).

La tercera línea formatea la marca de tiempo de publicación con un filtro, como ya sabemos.

La cuarta línea muestra el *título* de la entrada del blog como un `<h1>` encabezamiento. Hay una parte con la que quizá no estés familiarizado, y es `n:block="title"`. ¿Puedes adivinar lo que hace? Si has leído con atención las partes anteriores, hemos mencionado `n: attributes`. Este es otro ejemplo. Equivale a:

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

En palabras simples, *redefine* un bloque llamado `title`. El bloque está definido en la *plantilla de diseño* (`/app/UI/@layout.latte:11`) y, al igual que ocurre con la sobreescritura de programación orientada a objetos, se sobreescribe aquí. Por lo tanto, la página `<title>` contendrá el título de la entrada mostrada. Hemos sobreescrito el título de la página y todo lo que necesitábamos era `n:block="title"`. Genial, ¿eh?

La quinta y última línea de la plantilla muestra el contenido completo de tu post.


Comprobando el ID del post .[#toc-checking-post-id]
===================================================

¿Qué pasa si alguien altera la URL e inserta `id` que no existe? Deberíamos proporcionar al usuario un bonito error de "página no encontrada". Actualicemos el método render en `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;
}
```

Si la entrada no puede ser encontrada, llamando a `$this->error(...)` se mostrará una página 404 con un mensaje agradable y comprensible. Ten en cuenta que en tu entorno de desarrollo (en tu portátil), no verás la página de error. En su lugar, Tracy mostrará la excepción con todos los detalles, lo cual es bastante conveniente para el desarrollo. Puede comprobar ambos modos, simplemente cambie el valor pasado a `setDebugMode` en `Bootstrap.php`.


Resumen .[#toc-summary]
=======================

Tenemos una base de datos con entradas de blog y una aplicación web con dos vistas - la primera muestra el resumen de todas las entradas recientes y la segunda muestra una entrada específica.

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

Página individual

Vamos a añadir otra página a nuestro blog, que mostrará el contenido de una entrada del blog en particular.

Necesitamos crear un nuevo método de renderizado, que obtendrá una entrada de blog específica y la pasará a la plantilla. Tener esta vista en HomePresenter no es agradable porque se trata de una entrada de blog, no de la página principal. Por lo tanto, vamos a crear una nueva clase PostPresenter y colocarla en app/UI/Post/. Necesitará una conexión a la base de datos, por lo que pondremos el código de inyección a la base de datos allí de nuevo.

El PostPresenter debería verse así:

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

Tenemos que establecer un namespaces correcto App\UI\Post para nuestro presentador. Depende de la asignación del presentador.

El método renderShow requiere un argumento – el ID de la entrada a mostrar. Luego, carga la entrada desde la base de datos y pasa el resultado a la plantilla.

En la plantilla Home/default.latte añadimos un enlace a la acción Post:show:

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

La etiqueta {link} genera una dirección URL que apunta a la acción Post:show. Esta etiqueta también reenvía el ID del post como argumento.

Lo mismo podemos escribir en breve utilizando n:attribute:

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

El atributo n:href es similar a la etiqueta {link}.

La plantilla para la acción Post:show aún no existe. Podemos abrir un enlace a este post. Tracy mostrará un error, por qué Post/show.latte no existe. Si usted ve cualquier otro informe de error que probablemente tiene que activar mod_rewrite en su servidor web.

Así que vamos a crear Post/show.latte con este contenido:

{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>

Echemos un vistazo a las partes individuales.

La primera línea inicia la definición de un bloque con nombre llamado „contenido“ que vimos antes. Se mostrará en una plantilla de diseño. Como puedes ver, falta la etiqueta final {/block}. Es opcional.

La segunda línea proporciona un backlink a la lista de entradas del blog, para que el usuario pueda navegar sin problemas hacia adelante y hacia atrás en nuestro blog. Volvemos a utilizar el atributo n:href, por lo que Nette se encargará de generar la URL por nosotros. El enlace apunta a la acción default del presentador Home (también se podría escribir n:href="Home:", ya que la acción default se puede omitir).

La tercera línea formatea la marca de tiempo de publicación con un filtro, como ya sabemos.

La cuarta línea muestra el título de la entrada del blog como un <h1> encabezamiento. Hay una parte con la que quizá no estés familiarizado, y es n:block="title". ¿Puedes adivinar lo que hace? Si has leído con atención las partes anteriores, hemos mencionado n: attributes. Este es otro ejemplo. Equivale a:

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

En palabras simples, redefine un bloque llamado title. El bloque está definido en la plantilla de diseño (/app/UI/@layout.latte:11) y, al igual que ocurre con la sobreescritura de programación orientada a objetos, se sobreescribe aquí. Por lo tanto, la página <title> contendrá el título de la entrada mostrada. Hemos sobreescrito el título de la página y todo lo que necesitábamos era n:block="title". Genial, ¿eh?

La quinta y última línea de la plantilla muestra el contenido completo de tu post.

Comprobando el ID del post

¿Qué pasa si alguien altera la URL e inserta id que no existe? Deberíamos proporcionar al usuario un bonito error de „página no encontrada“. Actualicemos el método render en 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;
}

Si la entrada no puede ser encontrada, llamando a $this->error(...) se mostrará una página 404 con un mensaje agradable y comprensible. Ten en cuenta que en tu entorno de desarrollo (en tu portátil), no verás la página de error. En su lugar, Tracy mostrará la excepción con todos los detalles, lo cual es bastante conveniente para el desarrollo. Puede comprobar ambos modos, simplemente cambie el valor pasado a setDebugMode en Bootstrap.php.

Resumen

Tenemos una base de datos con entradas de blog y una aplicación web con dos vistas – la primera muestra el resumen de todas las entradas recientes y la segunda muestra una entrada específica.