Página inicial do Blog

Vamos criar a home page exibindo seus posts recentes.

Antes de começarmos, você deve saber pelo menos algumas noções básicas sobre o padrão de design Model-View-Presenter (similar ao MVC):

  • **Modelo*** – camada de manipulação de dados. Está completamente separado do resto da aplicação. Ele só se comunica com os apresentadores.
  • Veja – uma camada de definição front-end. Ela torna os dados solicitados ao usuário usando modelos.
  • Presente (ou Controlador) – uma camada de conexão. O apresentador conecta Modelo e Vista. Trata os pedidos, pede dados ao Modelo e depois os passa para a Vista atual.

No caso de uma aplicação muito simples como nosso blog, a camada Model consistirá apenas em consultas ao próprio banco de dados – não precisamos de nenhum código PHP extra para isso. Precisamos apenas criar camadas de Apresentador e Visualização. Na Nette, cada Apresentador tem suas próprias Views, portanto continuaremos com ambas simultaneamente.

Criação do banco de dados com Adminer

Para armazenar os dados, utilizaremos o banco de dados MySQL porque é a escolha mais comum entre os desenvolvedores web. Mas se você não gostar, sinta-se à vontade para usar um banco de dados de sua escolha.

Vamos preparar o banco de dados que irá armazenar nossos posts no blog. Podemos começar de forma muito simples – apenas com uma única tabela para postagens.

Para criar o banco de dados, podemos baixar o Adminer, ou você pode usar outra ferramenta para o gerenciamento do banco de dados.

Vamos abrir o Adminer e criar um novo banco de dados chamado quickstart.

Crie uma nova tabela chamada posts e adicione estas colunas:

  • id int, clique em autoincrement (AI)
  • title varchar, comprimento 255
  • content texto
  • created_at timestamp

Deveria ser assim:

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;

É muito importante utilizar o InnoDB armazenamento de mesa. Você verá o motivo mais tarde. Por enquanto, basta escolher isso e enviar. Você pode clicar em Salvar agora.

Tente adicionar alguns exemplos de posts no blog antes de implementarmos a capacidade de adicionar novos posts diretamente de nossa aplicação.

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

Conexão com o banco de dados

Agora, quando o banco de dados é criado e temos alguns posts nele, é o momento certo para exibi-los em nossa nova página brilhante.

Em primeiro lugar, precisamos informar nossa aplicação sobre qual banco de dados utilizar. A configuração da conexão do banco de dados é armazenada em config/common.neon. Defina a conexão DSN e suas credenciais. Deve ter este aspecto:

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

Esteja atento à indentação durante a edição deste arquivo. O formato NEON aceita ambos os espaços e abas, mas não ambos juntos! O arquivo de configuração no Projeto Web utiliza abas como padrão.

Injetando a conexão do banco de dados

O apresentador HomePresenter, que listará os artigos, precisa de uma conexão de banco de dados. Para recebê-la, escreva um construtor como este:

<?php
namespace App\Presenters;

use Nette;
use Nette\Application\UI\Form;

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

	// ...
}

Carregamento de postes a partir do banco de dados

Agora vamos buscar os posts no banco de dados e passá-los para o template, que então renderizará o código HTML. É para isso que serve o chamado método render:

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

O apresentador agora tem um método de renderização renderDefault() que passa dados para uma visualização chamada default. Os modelos do apresentador podem ser encontrados em app/Presenters/templates/{PresenterName}/{viewName}.latte, então neste caso o modelo será localizado em app/Presenters/templates/Home/default.latte. No modelo, uma variável chamada $posts está agora disponível, que contém os posts do banco de dados.

Modelo

Há um modelo genérico para toda a página (chamado layout, com cabeçalho, folhas de estilo, rodapé, …) e depois modelos específicos para cada visualização (por exemplo, para exibir a lista de posts do blog), que podem substituir algumas das peças do modelo de layout.

Por padrão, o modelo de layout está localizado em templates/@layout.latte, que contém:

...
{include content}
...

{include content} insere um bloco chamado content no modelo principal. Você pode defini-lo nos gabaritos de cada vista. Neste caso, editaremos o arquivo Home/default.latte desta forma:

{block content}
	Hello World
{/block}

Ele define o blococontent, que será inserido no layout. Se você atualizar o navegador, verá uma página com o texto “Hello world” (em código fonte também com cabeçalho e rodapé de página HTML definidos em @layout.latte).

Vamos exibir os posts do blog – editaremos o modelo desta forma:

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

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

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

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

Se você atualizar seu navegador, você verá a lista de seus posts no blog. A lista não é muito chique ou colorida, portanto, sinta-se à vontade para adicionar algum CSS brilhante a www/css/style.css e vinculá-lo em um layout:

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

A tag {foreach} itera todos os posts passados para a variável $posts e exibe um pedaço de código HTML para cada post. Assim como um código PHP faria.

A coisa |date é chamada de filtro. Os filtros são usados para formatar a saída. Este filtro particular converte uma data (por exemplo, 2013-04-12) para sua forma mais legível (12. 4. 2013). O filtro |truncate truncata a string no comprimento máximo especificado, e adiciona uma elipse à extremidade se a string for truncada. Como isto é uma prévia, não há sentido em exibir o conteúdo completo do artigo. Outros filtros padrão podem ser encontrados na documentação ou você pode criar o seu próprio, se necessário.

Mais uma coisa. Podemos tornar o código um pouco mais curto e, portanto, mais simples. Podemos substituir as etiquetas por n:atributos desta forma:

{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}</div>
	</div>
{/block}

O n:foreach, simplesmente envolve o div com um para cada bloco (ele faz exatamente a mesma coisa que o bloco de código anterior).

Sumário

Temos um banco de dados MySQL muito simples, com alguns posts em blogs. O aplicativo se conecta ao banco de dados e exibe uma lista simples dos posts.