Página principal del blog

Creemos la página principal, que mostrará sus artículos más recientes.

Antes de empezar debería conocer al menos algunos conceptos básicos del patrón de diseño Model-View-Presenter (parecido a MVC):

  • Model: la capa que trabaja con los datos. Está completamente separada del resto de la aplicación. Solo se comunica con el presenter.
  • View: la capa de presentación. Renderiza los datos solicitados mediante plantillas y se los muestra al usuario.
  • Presenter (o controlador): la capa de conexión. El presenter conecta el Model y la View. Gestiona las peticiones, le pide los datos al Model y después se los pasa a la View.

En el caso de una aplicación sencilla como nuestro blog, toda la capa del modelo consistirá solo en consultas a la base de datos; para eso todavía no necesitamos ningún código PHP adicional. Así que, para empezar, crearemos solo presenters y plantillas. En Nette, cada presenter tiene sus propias plantillas, así que las crearemos a la vez.

Crear la base de datos con Adminer

Para guardar los datos usaremos una base de datos MySQL, porque es la opción más habitual entre los desarrolladores web. Pero, si no quiere usarla, elija sin problema la base de datos que prefiera.

Preparemos la estructura de la base de datos que guardará los artículos de nuestro blog. Podemos empezar de forma muy sencilla, con una única tabla para los artículos.

Para crear la base de datos podemos descargar Adminer o usar otra herramienta de gestión de bases de datos que prefiera.

Abramos Adminer y creemos una base de datos nueva llamada quickstart.

Cree una tabla nueva llamada posts y añada estas columnas:

  • id int, marque autoincrement (AI)
  • title varchar, longitud 255
  • content text
  • created_at timestamp

Debería quedar así:

CREATE TABLE `posts` (
	`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`title` varchar(255) NOT NULL,
	`content` text NOT NULL,
	`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARSET=utf8;

Es muy importante usar el motor de almacenamiento InnoDB. El motivo lo verá más adelante. De momento, elíjalo sin más y pulse Guardar.

Pruebe a añadir a mano algunos artículos de ejemplo antes de que implementemos la creación de artículos nuevos directamente desde nuestra aplicación.

INSERT INTO `posts` (`id`, `title`, `content`, `created_at`) VALUES
(1,	'Article One',	'Lorem ipsum dolor one',	CURRENT_TIMESTAMP),
(2,	'Article Two',	'Lorem ipsum dolor two',	CURRENT_TIMESTAMP),
(3,	'Article Three',	'Lorem ipsum dolor three',	CURRENT_TIMESTAMP);

Conectarse a la base de datos

Ahora que la base de datos está creada y tenemos algunos artículos en ella, es el momento adecuado para mostrarlos en nuestra flamante página.

Primero tenemos que decirle a nuestra aplicación qué base de datos debe usar. La configuración de la conexión a la base de datos se establece en el archivo config/common.neon mediante el DSN y las credenciales. Debería quedar más o menos así:

database:
	dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
	user: *enter your username here*
	password: *enter your database password here*

Tenga cuidado con la indentación al editar este archivo. El formato NEON acepta tanto espacios como tabuladores, pero no ambos a la vez. El archivo de configuración predeterminado del Web Project usa tabuladores.

Inyectar la conexión a la base de datos

El presenter HomePresenter, que listará los artículos, necesita una conexión a la base de datos. Para recibirla usaremos el constructor así:

<?php
namespace App\Presentation\Home;

use Nette;

final class HomePresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	// ...
}

Cargar los artículos de la base de datos

Ahora obtengamos los artículos de la base de datos y pasémoselos a la plantilla, que después renderizará el código HTML. Para eso sirve el llamado método render:

public function renderDefault(): void
{
	$this->template->posts = $this->database
		->table('posts')
		->order('created_at DESC')
		->limit(5);
}

El presenter tiene ahora un método render renderDefault(), que pasa los datos de la base de datos a la plantilla (View). Las plantillas están en app/Presentation/{NombreDelPresenter}/{nombreDeLaVista}.latte, así que en este caso la plantilla está en app/Presentation/Home/default.latte. En la plantilla está ahora disponible una variable llamada $posts, que contiene los artículos obtenidos de la base de datos.

Plantilla

Para todo el sitio web tenemos una plantilla principal (llamada layout, que contiene la cabecera, los estilos, el pie, …) y plantillas concretas para cada vista (p. ej. para mostrar los artículos del blog), que pueden sobrescribir partes de la plantilla principal.

De forma predeterminada, la plantilla del layout está en app/Presentation/@layout.latte y contiene:

...
{include content}
...

La etiqueta {include content} inserta un bloque llamado content en la plantilla principal. Definiremos ese bloque en las plantillas de cada vista. En nuestro caso modificaremos el archivo Home/default.latte así:

{block content}
	Hello World
{/block}

Esto define el bloque content, que se insertará en el layout principal. Si vuelve a recargar el navegador, verá una página con el texto “Hello World” (en el código fuente, también con la cabecera y el pie HTML definidos en @layout.latte).

Mostremos los artículos del blog: modificaremos la plantilla así:

{block content}
	<h1>My Blog</h1>

	{foreach $posts as $post}
	<div class="post">
		<div class="date">{$post->created_at|date:'F j, Y'}</div>

		<h2>{$post->title}</h2>

		<div>{$post->content|truncate:256}</div>
	</div>
	{/foreach}
{/block}

Si recarga el navegador, verá la lista de los artículos de su blog. La lista todavía no es muy vistosa ni colorida, así que añada sin miedo unos bonitos estilos CSS al archivo www/css/style.css y enlácelo en el layout:

	...
	<link rel="stylesheet" href="{$basePath}/css/style.css">
</head>
...

La etiqueta {foreach} recorre todos los artículos pasados a la plantilla en la variable $posts y muestra un trozo de código HTML por cada artículo. Se comporta igual que el código PHP.

La notación |date: se llama filtro. Los filtros sirven para formatear la salida. Este filtro concreto convierte una fecha (p. ej. 2013-04-12) a su forma más legible (April 12, 2013). El filtro |truncate recorta la cadena a la longitud máxima indicada y añade puntos suspensivos (…) al final si la cadena se recorta. Como esto es una vista previa, no tiene sentido mostrar el contenido completo del artículo. Los demás filtros predeterminados los encontrará en la documentación, o puede crear los suyos si hace falta.

Una cosa más. Podemos hacer el código anterior más corto y sencillo. Lo conseguimos sustituyendo las etiquetas de Latte por n:atributos:

{block content}
	<h1>My Blog</h1>

	<div n:foreach="$posts as $post" class="post">
		<div class="date">{$post->created_at|date:'F j, Y'}</div>

		<h2>{$post->title}</h2>

		<div>{$post->content|truncate:256}</div>
	</div>
{/block}

El atributo n:foreach envuelve el bloque div con un bucle foreach (funciona exactamente igual que el código anterior).

Resumen

Ahora tenemos una base de datos MySQL muy sencilla con unos cuantos artículos. La aplicación se conecta a esa base de datos y muestra una lista simple de esos artículos en una plantilla.