Nette Documentation Preview

syntax
Blog kezdőlap
*************

.[perex]
Hozzuk létre a legutóbbi bejegyzéseinket megjelenítő kezdőlapot.


Mielőtt elkezdjük, legalább néhány alapismeretet tudnod kell a Model-View-Presenter tervezési mintáról (hasonlóan az MVC((Model-View-Controller))):

- **Modell** - adatmanipulációs réteg. Teljesen elkülönül az alkalmazás többi részétől. Csak a prezenterekkel kommunikál.

- **Nézet** - egy front-end definíciós réteg. Sablonok segítségével megjeleníti a felhasználó számára a kért adatokat.

- **Presenter** (vagy Controller) - egy kapcsolati réteg. A bemutató összeköti a modellt és a nézetet. Kezeli a kéréseket, adatokat kér a Modelltől, majd átadja azokat az aktuális Nézetnek.


Egy olyan nagyon egyszerű alkalmazás esetén, mint a mi blogunk, a Model réteg valójában csak magának az adatbázisnak a lekérdezéséből áll - ehhez nincs szükségünk semmilyen extra PHP kódra. Nekünk csak a Presenter és a View rétegeket kell létrehoznunk. A Nette-ben minden Presenterhez saját Views tartozik, így mindkettővel egyszerre fogjuk folytatni.


Az adatbázis létrehozása az Adminerrel .[#toc-creating-the-database-with-adminer]
=================================================================================

Az adatok tárolására a MySQL adatbázist fogjuk használni, mivel ez a legelterjedtebb választás a webfejlesztők körében. De ha nem tetszik, nyugodtan használjon egy tetszőleges adatbázist.

Készítsük el az adatbázist, amely a blogbejegyzéseinket fogja tárolni. Kezdhetjük nagyon egyszerűen - csak egyetlen táblával a bejegyzéseknek.

Az adatbázis létrehozásához letölthetjük [az Adminert |https://www.adminer.org], vagy használhatunk más adatbázis-kezelő eszközt is.


Nyissuk meg az Adminert, és hozzunk létre egy új adatbázist `quickstart` néven.

Hozzunk létre egy új táblát `posts` néven, és adjuk hozzá ezeket az oszlopokat:
- `id` int, kattintsunk az autoincrement (AI) gombra.
- `title` varchar, hossza 255
- `content` szöveg
- `created_at` timestamp

Így kell kinéznie:

[* adminer-posts.webp *]

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

.[caution]
Nagyon fontos, hogy az **InnoDB** tábla tárolását használjuk. Később látni fogja az okát. Egyelőre csak válassza ezt és küldje el. Most már megnyomhatja a Mentés gombot.

Próbáljon ki néhány minta blogbejegyzés hozzáadását, mielőtt megvalósítjuk az új bejegyzések hozzáadásának képességét közvetlenül az alkalmazásunkból.

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


Csatlakozás az adatbázishoz .[#toc-connecting-to-the-database]
==============================================================

Most, hogy az adatbázis elkészült, és van benne néhány bejegyzés, itt az ideje, hogy megjelenítsük őket az új, csillogó oldalunkon.

Először is meg kell mondanunk az alkalmazásunknak, hogy melyik adatbázist használja. Az adatbázis-kapcsolat konfigurációját a `config/common.neon` oldalon tároljuk. Állítsuk be a DSN((Data Source Name)) kapcsolatot és a hitelesítő adatokat. Így kell kinéznie:

```neon .{file:config/common.neon}
database:
	dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
	user: *enter user name*
	password: *enter password here*
```

.[note]
Figyeljen a behúzásokra a fájl szerkesztése közben. A [NEON formátum |neon:format] elfogadja a szóközöket és a tabulátorokat is, de nem mindkettőt együtt! A webes projekt konfigurációs fájlja alapértelmezés szerint tabulátorokat használ.


Az adatbázis-csatlakozás beillesztése .[#toc-injecting-the-database-connection]
===============================================================================

A cikkeket listázó `HomePresenter` bemutatónak szüksége van egy adatbázis-kapcsolatra. Ahhoz, hogy megkapja, írjunk egy ilyen konstruktort:

```php .{file:app/UI/Home/HomePresenter.php}
<?php
namespace App\UI\Home;

use Nette;

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

	// ...
}
```


Hozzászólások betöltése az adatbázisból .[#toc-loading-posts-from-the-database]
===============================================================================

Most pedig hívjuk le a bejegyzéseket az adatbázisból, és adjuk át a sablonhoz, amely ezután megjeleníti a HTML kódot. Erre szolgál az úgynevezett *render* metódus:

```php .{file:app/UI/Home/HomePresenter.php}
public function renderDefault(): void
{
	$this->template->posts = $this->database
		->table('posts')
		->order('created_at DESC')
		->limit(5);
}
```

A prezenternek most egy renderelési metódusa van: `renderDefault()`, amely az adatokat a `default` nevű nézetnek adja át. A prezenter sablonok a `app/UI/{PresenterName}/{viewName}.latte` oldalon találhatók, így ebben az esetben a sablon a `app/UI/Home/default.latte` oldalon lesz. A sablonban most már elérhető egy `$posts` nevű változó, amely az adatbázisból származó bejegyzéseket tartalmazza.


Sablon .[#toc-template]
=======================

Van egy általános sablon az egész oldalra (az úgynevezett *layout*, fejléccel, stíluslapokkal, lábléccel, ...), majd specifikus sablonok az egyes nézetekhez (pl. a blogbejegyzések listájának megjelenítéséhez), amelyek felülírhatják a layout sablon egyes részeit.

Alapértelmezés szerint az elrendezési sablon a `app/UI/@layout.latte` oldalon található, amely a következőket tartalmazza:

```latte .{file:app/UI/@layout.latte}
...
{include content}
...
```

`{include content}` beilleszt egy `content` nevű blokkot a fő sablonba. Ezt az egyes nézetek sablonjaiban határozhatja meg. Ebben az esetben a `Home/default.latte` fájlt így szerkesztjük:

```latte .{file:app/UI/Home/default.latte}
{block content}
	Hello World
{/block}
```

Ez határozza meg a *tartalom* [blokkot |latte:tags#block], amely be lesz illesztve az elrendezésbe. Ha frissítjük a böngészőt, egy "Hello world" szövegű oldalt fogunk látni (a forráskódban a `@layout.latte`) által definiált HTML fejléccel és lábléccel is.

Jelenítsük meg a blogbejegyzéseket - a sablont így szerkesztjük:

```latte .{file:app/UI/Home/default.latte}
{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}
```

Ha frissítjük a böngészőnket, megjelenik a blogbejegyzések listája. A lista nem túl díszes vagy színes, ezért nyugodtan adjunk hozzá néhány [csillogó CSS-t |https://github.com/nette-examples/quickstart/blob/v4.0/www/css/style.css] a `www/css/style.css` címre, és linkeljük be egy elrendezésbe:

```latte .{file:app/UI/@layout.latte}
	...
	<link rel="stylesheet" href="{$basePath}/css/style.css">
</head>
...
```

A `{foreach}` címke a `$posts` változóban a sablonhoz átadott összes bejegyzést átnézi, és minden egyes bejegyzéshez megjelenít egy darab HTML-kódot. Pontosan úgy, mint egy PHP kód.

A `|date` dolgot szűrőnek hívják. A szűrők a kimenet formázására szolgálnak. Ez a konkrét szűrő egy dátumot (pl. `2013-04-12`) alakít át olvashatóbb formájúra (`12. 4. 2013`). A `|truncate` szűrő a megadott maximális hosszúságra vágja le a karakterláncot, és egy ellipszist ad a végéhez, ha a karakterláncot lecsonkolja. Mivel ez egy előnézet, nincs értelme a cikk teljes tartalmát megjeleníteni. Más alapértelmezett szűrők megtalálhatók [a dokumentációban |latte:filters], vagy szükség esetén létrehozhat saját szűrőket.

Még egy dolog. A kódot egy kicsit rövidebbé és ezáltal egyszerűbbé tehetjük. A *Latte címkéket* helyettesíthetjük *n:attribútumokkal*, így:

```latte .{file:app/UI/Home/default.latte}
{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}
```

A `n:foreach`, egyszerűen körbecsomagolja a *div*-et egy *foreach* blokkal (pontosan ugyanazt teszi, mint az előző kódblokk).


Összefoglaló .[#toc-summary]
============================

Van egy nagyon egyszerű MySQL adatbázisunk, amelyben néhány blogbejegyzés található. Az alkalmazás csatlakozik az adatbázishoz, és megjeleníti a bejegyzések egyszerű listáját.

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

Blog kezdőlap

Hozzuk létre a legutóbbi bejegyzéseinket megjelenítő kezdőlapot.

Mielőtt elkezdjük, legalább néhány alapismeretet tudnod kell a Model-View-Presenter tervezési mintáról (hasonlóan az MVC):

  • Modell – adatmanipulációs réteg. Teljesen elkülönül az alkalmazás többi részétől. Csak a prezenterekkel kommunikál.
  • Nézet – egy front-end definíciós réteg. Sablonok segítségével megjeleníti a felhasználó számára a kért adatokat.
  • Presenter (vagy Controller) – egy kapcsolati réteg. A bemutató összeköti a modellt és a nézetet. Kezeli a kéréseket, adatokat kér a Modelltől, majd átadja azokat az aktuális Nézetnek.

Egy olyan nagyon egyszerű alkalmazás esetén, mint a mi blogunk, a Model réteg valójában csak magának az adatbázisnak a lekérdezéséből áll – ehhez nincs szükségünk semmilyen extra PHP kódra. Nekünk csak a Presenter és a View rétegeket kell létrehoznunk. A Nette-ben minden Presenterhez saját Views tartozik, így mindkettővel egyszerre fogjuk folytatni.

Az adatbázis létrehozása az Adminerrel

Az adatok tárolására a MySQL adatbázist fogjuk használni, mivel ez a legelterjedtebb választás a webfejlesztők körében. De ha nem tetszik, nyugodtan használjon egy tetszőleges adatbázist.

Készítsük el az adatbázist, amely a blogbejegyzéseinket fogja tárolni. Kezdhetjük nagyon egyszerűen – csak egyetlen táblával a bejegyzéseknek.

Az adatbázis létrehozásához letölthetjük az Adminert, vagy használhatunk más adatbázis-kezelő eszközt is.

Nyissuk meg az Adminert, és hozzunk létre egy új adatbázist quickstart néven.

Hozzunk létre egy új táblát posts néven, és adjuk hozzá ezeket az oszlopokat:

  • id int, kattintsunk az autoincrement (AI) gombra.
  • title varchar, hossza 255
  • content szöveg
  • created_at timestamp

Így kell kinéznie:

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;

Nagyon fontos, hogy az InnoDB tábla tárolását használjuk. Később látni fogja az okát. Egyelőre csak válassza ezt és küldje el. Most már megnyomhatja a Mentés gombot.

Próbáljon ki néhány minta blogbejegyzés hozzáadását, mielőtt megvalósítjuk az új bejegyzések hozzáadásának képességét közvetlenül az alkalmazásunkból.

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

Csatlakozás az adatbázishoz

Most, hogy az adatbázis elkészült, és van benne néhány bejegyzés, itt az ideje, hogy megjelenítsük őket az új, csillogó oldalunkon.

Először is meg kell mondanunk az alkalmazásunknak, hogy melyik adatbázist használja. Az adatbázis-kapcsolat konfigurációját a config/common.neon oldalon tároljuk. Állítsuk be a DSN kapcsolatot és a hitelesítő adatokat. Így kell kinéznie:

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

Figyeljen a behúzásokra a fájl szerkesztése közben. A NEON formátum elfogadja a szóközöket és a tabulátorokat is, de nem mindkettőt együtt! A webes projekt konfigurációs fájlja alapértelmezés szerint tabulátorokat használ.

Az adatbázis-csatlakozás beillesztése

A cikkeket listázó HomePresenter bemutatónak szüksége van egy adatbázis-kapcsolatra. Ahhoz, hogy megkapja, írjunk egy ilyen konstruktort:

<?php
namespace App\UI\Home;

use Nette;

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

	// ...
}

Hozzászólások betöltése az adatbázisból

Most pedig hívjuk le a bejegyzéseket az adatbázisból, és adjuk át a sablonhoz, amely ezután megjeleníti a HTML kódot. Erre szolgál az úgynevezett render metódus:

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

A prezenternek most egy renderelési metódusa van: renderDefault(), amely az adatokat a default nevű nézetnek adja át. A prezenter sablonok a app/UI/{PresenterName}/{viewName}.latte oldalon találhatók, így ebben az esetben a sablon a app/UI/Home/default.latte oldalon lesz. A sablonban most már elérhető egy $posts nevű változó, amely az adatbázisból származó bejegyzéseket tartalmazza.

Sablon

Van egy általános sablon az egész oldalra (az úgynevezett layout, fejléccel, stíluslapokkal, lábléccel, …), majd specifikus sablonok az egyes nézetekhez (pl. a blogbejegyzések listájának megjelenítéséhez), amelyek felülírhatják a layout sablon egyes részeit.

Alapértelmezés szerint az elrendezési sablon a app/UI/@layout.latte oldalon található, amely a következőket tartalmazza:

...
{include content}
...

{include content} beilleszt egy content nevű blokkot a fő sablonba. Ezt az egyes nézetek sablonjaiban határozhatja meg. Ebben az esetben a Home/default.latte fájlt így szerkesztjük:

{block content}
	Hello World
{/block}

Ez határozza meg a tartalom blokkot, amely be lesz illesztve az elrendezésbe. Ha frissítjük a böngészőt, egy „Hello world“ szövegű oldalt fogunk látni (a forráskódban a @layout.latte) által definiált HTML fejléccel és lábléccel is.

Jelenítsük meg a blogbejegyzéseket – a sablont így szerkesztjük:

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

Ha frissítjük a böngészőnket, megjelenik a blogbejegyzések listája. A lista nem túl díszes vagy színes, ezért nyugodtan adjunk hozzá néhány csillogó CSS-t a www/css/style.css címre, és linkeljük be egy elrendezésbe:

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

A {foreach} címke a $posts változóban a sablonhoz átadott összes bejegyzést átnézi, és minden egyes bejegyzéshez megjelenít egy darab HTML-kódot. Pontosan úgy, mint egy PHP kód.

A |date dolgot szűrőnek hívják. A szűrők a kimenet formázására szolgálnak. Ez a konkrét szűrő egy dátumot (pl. 2013-04-12) alakít át olvashatóbb formájúra (12. 4. 2013). A |truncate szűrő a megadott maximális hosszúságra vágja le a karakterláncot, és egy ellipszist ad a végéhez, ha a karakterláncot lecsonkolja. Mivel ez egy előnézet, nincs értelme a cikk teljes tartalmát megjeleníteni. Más alapértelmezett szűrők megtalálhatók a dokumentációban, vagy szükség esetén létrehozhat saját szűrőket.

Még egy dolog. A kódot egy kicsit rövidebbé és ezáltal egyszerűbbé tehetjük. A Latte címkéket helyettesíthetjük n:attribútumokkal, így:

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

A n:foreach, egyszerűen körbecsomagolja a div-et egy foreach blokkal (pontosan ugyanazt teszi, mint az előző kódblokk).

Összefoglaló

Van egy nagyon egyszerű MySQL adatbázisunk, amelyben néhány blogbejegyzés található. Az alkalmazás csatlakozik az adatbázishoz, és megjeleníti a bejegyzések egyszerű listáját.