Strona główna bloga
Teraz stwórzmy stronę główną pokazującą najnowsze posty.
Zanim zaczniemy, musimy znać przynajmniej podstawy wzorca projektowego Model-Widok-Prezenter (podobnego do MVC:
- Model – warstwa, która pracuje z danymi. Jest on całkowicie oddzielony od reszty aplikacji. Komunikuje się tylko z prezenterem.
- Widok – warstwa front-end. Renderuje wymagane dane za pomocą szablonów i wyświetla je użytkownikowi.
- Prezenter (lub Kontroler) – warstwa łącząca. Prezenter łączy Model i Widok. Przetwarza on żądania, zapytuje Model o dane i zwraca je z powrotem do Widoku.
W przypadku prostych aplikacji, jakimi będzie nasz blog, cała warstwa modelu będzie składać się z samych zapytań do bazy danych – nie potrzebujemy do tego jeszcze żadnego dodatkowego kodu. Na początek więc stworzymy tylko prezentery i szablony. W Nette każdy prezenter ma swoje szablony, więc będziemy je tworzyć jednocześnie.
Tworzenie bazy danych za pomocą Adminera
Do przechowywania danych wykorzystamy bazę MySQL, ponieważ jest ona najczęściej spotykana wśród programistów aplikacji internetowych. Jeśli jednak nie chcesz z niego korzystać, nie krępuj się i wybierz dowolną bazę danych.
Teraz przygotujemy strukturę bazy danych, w której będą przechowywane nasze artykuły na blogu. Zaczniemy bardzo prosto – stworzymy tylko jedną tabelę dla postów.
Aby stworzyć bazę danych, możemy pobrać Adminera, lub inne ulubione narzędzie do zarządzania bazą danych.
Otwórz Adminera i utwórz nową bazę danych o nazwie quickstart
.
Utwórz nową tabelę o nazwie posts
z następującymi kolumnami:
id
int, sprawdzenie autoinkrementacji (AI)title
varchar, długość 255content
tekstcreated_at
znacznik czasu
Powstała struktura powinna wyglądać tak:
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;
Naprawdę ważne jest, aby używać InnoDB storage. Za chwilę pokażemy dlaczego. Na razie wystarczy ją zaznaczyć i kliknąć Zapisz.
Zanim stworzymy możliwość dodawania artykułów do bazy danych za pomocą aplikacji, dodajmy ręcznie kilka przykładowych artykułów z bloga.
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);
Podłączenie do bazy danych
Teraz, gdy baza danych jest utworzona i mamy kilka artykułów w niej zapisanych, to dobry moment, aby wyświetlić je na naszej pięknej, nowej stronie.
Najpierw musimy powiedzieć aplikacji, z jakiej bazy danych ma korzystać. Konfigurujemy połączenie z bazą danych w pliku
config/common.neon
używając DSN i poświadczeń logowania.
Powinno to wyglądać coś takiego:
database:
dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
user: *zde vložte jméno uživatele*
password: *zde vložte heslo k databázi*
Podczas edycji tego pliku zwróć uwagę na wcięcie linii. Format NEON akceptuje zarówno wcięcie spacji, jak i wcięcie tabulatora, ale nie oba jednocześnie. Domyślny plik konfiguracyjny w Web Project wykorzystuje zakładki.
Przekazanie połączenia z bazą danych
Prezenter HomePresenter
, który będzie obsługiwał zestawienie artykułów, potrzebuje połączenia z bazą
danych. Aby go uzyskać, użyjemy konstruktora, który wygląda tak:
<?php
namespace App\UI\Home;
use Nette;
final class HomePresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private Nette\Database\Explorer $database,
) {
}
// ...
}
Ładowanie postów z bazy danych
Teraz ładujemy posty z bazy danych i wysyłamy je do szablonu, który następnie renderuje je jako kod HTML. Do tego właśnie służy tzw. metoda render:
public function renderDefault(): void
{
$this->template->posts = $this->database
->table('posts')
->order('created_at DESC')
->limit(5);
}
Presenter zawiera teraz jedną metodę render renderDefault()
, która przekazuje dane z bazy danych do szablonu
(View). Szablony znajdują się w app/UI/{PresenterName}/{viewName}.latte
, więc w tym przypadku szablon znajduje
się w app/UI/Home/default.latte
. Szablon będzie miał teraz zmienną $posts
, która zawiera posty
pobrane z bazy danych.
Szablon
Dla całej strony mamy szablon główny (który nazywa się layout, zawiera nagłówek, style, stopkę,…) oraz specyficzne szablony dla każdego widoku (View) (np. do wyświetlania postów na blogu), które mogą nadpisywać niektóre części szablonu głównego.
Domyślnie szablon układu znajduje się w app/UI/@layout.latte
i zawiera:
...
{include content}
...
Wpis {include content}
wstawia do głównego szablonu blok o nazwie content
. zdefiniujemy to w
poszczególnych szablonach widoku (View). W naszym przypadku zmodyfikujemy plik Home/default.latte
w następujący
sposób:
{block content}
Hello World
{/block}
W ten sposób zdefiniowaliśmy blok content, który zostanie
wstawiony do głównego układu. Jeśli ponownie odświeżymy przeglądarkę, zobaczymy stronę z tekstem „Hello World“ (w
kodzie źródłowym oraz z nagłówkiem i stopką HTML zdefiniowanymi w @layout.latte
).
Wyświetlmy wpisy na blogu – zmodyfikujmy szablon w następujący sposób:
{block content}
<h1>Můj 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}
Jeśli odświeżymy przeglądarkę, zobaczymy zestawienie wszystkich postów. Listing nie jest jeszcze zbyt ładny, nawet nie
jest kolorowy, więc możemy dodać kilka stylów CSS do pliku
www/css/style.css
i połączyć go w układzie:
...
<link rel="stylesheet" href="{$basePath}/css/style.css">
</head>
...
Znacznik {foreach}
iteruje po wszystkich postach, które przekazaliśmy do szablonu w zmiennej
$posts
, i dla każdego z nich renderuje dany fragment HTML. Zachowuje się dokładnie jak kod PHP.
Wpis |date:
nazywamy filtrem. Filtry mają za zadanie sformatować dane wyjściowe. Ten konkretny filtr konwertuje
datę (np. 2013-04-12
) na jej bardziej czytelną postać (April 12, 2013
). Filtr |truncate
obcina łańcuch do maksymalnej podanej długości i dodaje na końcu trójkę, jeśli łańcuch jest obcięty. Ponieważ jest to
podgląd, nie ma sensu pokazywać całej treści artykułu. Inne domyślne filtry można znaleźć w dokumentacji lub w razie potrzeby można stworzyć własne.
Jeszcze jedna rzecz. Możemy skrócić i uprościć poprzedni kod. Możemy to zrobić zastępując znaczniki Latte przez n:attributes:
{block content}
<h1>Můj 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}
Atrybut n:foreach
owija div blokiem foreach (działa dokładnie tak samo jak poprzedni kod).
Streszczenie.
Mamy teraz bardzo prostą bazę danych MySQL z kilkoma postami. Aplikacja łączy się z tą bazą danych i wyprowadza prostą listę tych postów do szablonu.