Nette Documentation Preview

syntax
Αρχική σελίδα Blog
******************

.[perex]
Ας δημιουργήσουμε την αρχική σελίδα που εμφανίζει τις πρόσφατες δημοσιεύσεις σας.


Πριν ξεκινήσουμε, θα πρέπει να γνωρίζετε τουλάχιστον κάποια βασικά στοιχεία για το πρότυπο σχεδίασης Model-View-Presenter (παρόμοιο με το MVC((Model-View-Controller))):

- **Μοντέλο** - επίπεδο επεξεργασίας δεδομένων. Είναι πλήρως διαχωρισμένο από την υπόλοιπη εφαρμογή. Επικοινωνεί μόνο με τους παρουσιαστές.

- **View** - ένα επίπεδο ορισμού front-end. Αποδίδει τα ζητούμενα δεδομένα στο χρήστη χρησιμοποιώντας πρότυπα.

- **Παρουσιαστής** (ή ελεγκτής) - ένα επίπεδο σύνδεσης. Ο παρουσιαστής συνδέει το μοντέλο και την προβολή. Χειρίζεται τα αιτήματα, ζητά από το Μοντέλο δεδομένα και στη συνέχεια τα μεταβιβάζει στην τρέχουσα Προβολή.


Στην περίπτωση μιας πολύ απλής εφαρμογής όπως το ιστολόγιό μας, το επίπεδο Μοντέλου θα αποτελείται στην πραγματικότητα μόνο από ερωτήματα προς την ίδια τη βάση δεδομένων - δεν χρειαζόμαστε επιπλέον κώδικα PHP γι' αυτό. Το μόνο που χρειάζεται είναι να δημιουργήσουμε τα στρώματα Presenter και View. Στη Nette, κάθε Presenter έχει τα δικά του Views, οπότε θα συνεχίσουμε και με τα δύο ταυτόχρονα.


Δημιουργία της βάσης δεδομένων με το Adminer .[#toc-creating-the-database-with-adminer]
=======================================================================================

Για την αποθήκευση των δεδομένων, θα χρησιμοποιήσουμε τη βάση δεδομένων MySQL επειδή είναι η πιο συνηθισμένη επιλογή μεταξύ των προγραμματιστών ιστοσελίδων. Αλλά αν δεν σας αρέσει, μπορείτε να χρησιμοποιήσετε μια βάση δεδομένων της επιλογής σας.

Ας προετοιμάσουμε τη βάση δεδομένων που θα αποθηκεύει τις αναρτήσεις του ιστολογίου μας. Μπορούμε να ξεκινήσουμε πολύ απλά - μόνο με έναν ενιαίο πίνακα για τις αναρτήσεις.

Για να δημιουργήσουμε τη βάση δεδομένων μπορούμε να κατεβάσουμε [το Adminer |https://www.adminer.org], ή μπορείτε να χρησιμοποιήσετε κάποιο άλλο εργαλείο για τη διαχείριση βάσεων δεδομένων.


Ας ανοίξουμε το Adminer και ας δημιουργήσουμε μια νέα βάση δεδομένων με όνομα `quickstart`.

Δημιουργήστε έναν νέο πίνακα με το όνομα `posts` και προσθέστε αυτές τις στήλες:
- `id` int, κάντε κλικ στο autoincrement (AI)
- `title` varchar, μήκος 255
- `content` text
- `created_at` timestamp

Θα πρέπει να μοιάζει ως εξής:

[* 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]
Είναι πολύ σημαντικό να χρησιμοποιείτε τον αποθηκευτικό χώρο του πίνακα **InnoDB**. Θα δείτε τον λόγο αργότερα. Προς το παρόν, απλά επιλέξτε αυτό και στείλτε το. Μπορείτε να πατήσετε Save τώρα.

Δοκιμάστε να προσθέσετε μερικές δειγματικές αναρτήσεις στο ιστολόγιο πριν υλοποιήσουμε τη δυνατότητα προσθήκης νέων αναρτήσεων απευθείας από την εφαρμογή μας.

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


Σύνδεση με τη βάση δεδομένων .[#toc-connecting-to-the-database]
===============================================================

Τώρα, όταν η βάση δεδομένων έχει δημιουργηθεί και έχουμε κάποιες αναρτήσεις σε αυτήν, είναι η κατάλληλη στιγμή να τις εμφανίσουμε στη νέα μας λαμπερή σελίδα.

Πρώτα, πρέπει να πούμε στην εφαρμογή μας ποια βάση δεδομένων θα χρησιμοποιήσει. Η ρύθμιση της σύνδεσης με τη βάση δεδομένων αποθηκεύεται στο `config/common.neon`. Ορίστε τη σύνδεση DSN((Data Source Name)) και τα διαπιστευτήριά σας. Θα πρέπει να μοιάζει κάπως έτσι:

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

.[note]
Προσέξτε τις εσοχές κατά την επεξεργασία αυτού του αρχείου. Η [μορφή NEON |neon:format] δέχεται τόσο κενά όσο και ταμπέλες, αλλά όχι και τα δύο μαζί! Το αρχείο ρυθμίσεων στο Web Project χρησιμοποιεί τα tabs ως προεπιλογή.


Εισαγωγή της σύνδεσης της βάσης δεδομένων .[#toc-injecting-the-database-connection]
===================================================================================

Ο παρουσιαστής `HomePresenter`, ο οποίος θα απαριθμεί τα άρθρα, χρειάζεται μια σύνδεση με τη βάση δεδομένων. Για να τη λάβει, γράψτε έναν κατασκευαστή όπως αυτός:

```php .{file:app/Presenters/HomePresenter.php}
<?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,
	) {
	}

	// ...
}
```


Φόρτωση αναρτήσεων από τη βάση δεδομένων .[#toc-loading-posts-from-the-database]
================================================================================

Τώρα ας φέρουμε τις αναρτήσεις από τη βάση δεδομένων και ας τις περάσουμε στο πρότυπο, το οποίο στη συνέχεια θα αποδώσει τον κώδικα HTML. Γι' αυτό το σκοπό υπάρχει η λεγόμενη μέθοδος *render*:

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

Ο παρουσιαστής έχει τώρα μια μέθοδο render `renderDefault()` που περνάει τα δεδομένα σε μια προβολή που ονομάζεται `default`. Τα πρότυπα του παρουσιαστή μπορούν να βρεθούν στο `app/Presenters/templates/{PresenterName}/{viewName}.latte`, οπότε σε αυτή την περίπτωση το πρότυπο θα βρίσκεται στο `app/Presenters/templates/Home/default.latte`. Στο πρότυπο, μια μεταβλητή με το όνομα `$posts` είναι τώρα διαθέσιμη, η οποία περιέχει τις δημοσιεύσεις από τη βάση δεδομένων.


Πρότυπο .[#toc-template]
========================

Υπάρχει ένα γενικό πρότυπο για ολόκληρη τη σελίδα (που ονομάζεται *layout*, με κεφαλίδα, φύλλα στυλ, υποσέλιδο, ...) και στη συνέχεια ειδικά πρότυπα για κάθε προβολή (π.χ. για την εμφάνιση της λίστας των αναρτήσεων του ιστολογίου), τα οποία μπορούν να παρακάμψουν ορισμένα τμήματα του προτύπου layout.

Από προεπιλογή, το πρότυπο διάταξης βρίσκεται στο `templates/@layout.latte`, το οποίο περιέχει:

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

`{include content}` εισάγει ένα μπλοκ με το όνομα `content` στο κύριο πρότυπο. Μπορείτε να το ορίσετε στα πρότυπα κάθε προβολής. Σε αυτή την περίπτωση, θα επεξεργαστούμε το αρχείο `Home/default.latte` ως εξής:

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

Ορίζει το [μπλοκ |latte:tags#block]*περιεχόμενο*, το οποίο θα εισαχθεί στη διάταξη. Αν ανανεώσετε το πρόγραμμα περιήγησης, θα δείτε μια σελίδα με το κείμενο "Hello world" (στον πηγαίο κώδικα επίσης με HTML κεφαλίδα και υποσέλιδο που ορίζονται στο `@layout.latte`).

Ας εμφανίσουμε τις αναρτήσεις του ιστολογίου - θα επεξεργαστούμε το πρότυπο ως εξής:

```latte .{file:app/Presenters/templates/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}
```

Αν ανανεώσετε το πρόγραμμα περιήγησής σας, θα δείτε τη λίστα με τις αναρτήσεις του ιστολογίου σας. Η λίστα δεν είναι πολύ φανταχτερή ή πολύχρωμη, γι' αυτό μη διστάσετε να προσθέσετε κάποιο [λαμπερό CSS |https://github.com/nette-examples/quickstart/blob/v4.0/www/css/style.css] στο `www/css/style.css` και να το συνδέσετε σε μια διάταξη:

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

Η ετικέτα `{foreach}` επαναλαμβάνει όλες τις δημοσιεύσεις που έχουν περάσει στο πρότυπο στη μεταβλητή `$posts` και εμφανίζει ένα κομμάτι κώδικα HTML για κάθε δημοσίευση. Ακριβώς όπως θα έκανε ένας κώδικας PHP.

Το `|date` ονομάζεται φίλτρο. Τα φίλτρα χρησιμοποιούνται για τη μορφοποίηση της εξόδου. Το συγκεκριμένο φίλτρο μετατρέπει μια ημερομηνία (π.χ. `2013-04-12`) στην πιο ευανάγνωστη μορφή της (`12. 4. 2013`). Το φίλτρο `|truncate` περικόπτει τη συμβολοσειρά στο καθορισμένο μέγιστο μήκος και προσθέτει μια έλλειψη στο τέλος, αν η συμβολοσειρά είναι περικομμένη. Δεδομένου ότι πρόκειται για προεπισκόπηση, δεν υπάρχει λόγος να εμφανιστεί το πλήρες περιεχόμενο του άρθρου. Άλλα προεπιλεγμένα φίλτρα [μπορείτε να βρείτε στην τεκμηρίωση |latte:filters] ή μπορείτε να δημιουργήσετε τα δικά σας αν χρειάζεται.

Και κάτι ακόμα. Μπορούμε να κάνουμε τον κώδικα λίγο πιο σύντομο και συνεπώς πιο απλό. Μπορούμε να αντικαταστήσουμε τα *Latte tags* με *n:attributes* όπως παρακάτω:

```latte .{file:app/Presenters/templates/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}
```

Το `n:foreach`, απλά τυλίγει το *div* με ένα μπλοκ *foreach* (κάνει ακριβώς το ίδιο πράγμα με το προηγούμενο μπλοκ κώδικα).


Περίληψη .[#toc-summary]
========================

Έχουμε μια πολύ απλή βάση δεδομένων MySQL με μερικές αναρτήσεις σε ιστολόγια. Η εφαρμογή συνδέεται με τη βάση δεδομένων και εμφανίζει μια απλή λίστα με τις αναρτήσεις.

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

Αρχική σελίδα Blog

Ας δημιουργήσουμε την αρχική σελίδα που εμφανίζει τις πρόσφατες δημοσιεύσεις σας.

Πριν ξεκινήσουμε, θα πρέπει να γνωρίζετε τουλάχιστον κάποια βασικά στοιχεία για το πρότυπο σχεδίασης Model-View-Presenter (παρόμοιο με το MVC):

  • Μοντέλο – επίπεδο επεξεργασίας δεδομένων. Είναι πλήρως διαχωρισμένο από την υπόλοιπη εφαρμογή. Επικοινωνεί μόνο με τους παρουσιαστές.
  • View – ένα επίπεδο ορισμού front-end. Αποδίδει τα ζητούμενα δεδομένα στο χρήστη χρησιμοποιώντας πρότυπα.
  • Παρουσιαστής (ή ελεγκτής) – ένα επίπεδο σύνδεσης. Ο παρουσιαστής συνδέει το μοντέλο και την προβολή. Χειρίζεται τα αιτήματα, ζητά από το Μοντέλο δεδομένα και στη συνέχεια τα μεταβιβάζει στην τρέχουσα Προβολή.

Στην περίπτωση μιας πολύ απλής εφαρμογής όπως το ιστολόγιό μας, το επίπεδο Μοντέλου θα αποτελείται στην πραγματικότητα μόνο από ερωτήματα προς την ίδια τη βάση δεδομένων – δεν χρειαζόμαστε επιπλέον κώδικα PHP γι' αυτό. Το μόνο που χρειάζεται είναι να δημιουργήσουμε τα στρώματα Presenter και View. Στη Nette, κάθε Presenter έχει τα δικά του Views, οπότε θα συνεχίσουμε και με τα δύο ταυτόχρονα.

Δημιουργία της βάσης δεδομένων με το Adminer

Για την αποθήκευση των δεδομένων, θα χρησιμοποιήσουμε τη βάση δεδομένων MySQL επειδή είναι η πιο συνηθισμένη επιλογή μεταξύ των προγραμματιστών ιστοσελίδων. Αλλά αν δεν σας αρέσει, μπορείτε να χρησιμοποιήσετε μια βάση δεδομένων της επιλογής σας.

Ας προετοιμάσουμε τη βάση δεδομένων που θα αποθηκεύει τις αναρτήσεις του ιστολογίου μας. Μπορούμε να ξεκινήσουμε πολύ απλά – μόνο με έναν ενιαίο πίνακα για τις αναρτήσεις.

Για να δημιουργήσουμε τη βάση δεδομένων μπορούμε να κατεβάσουμε το Adminer, ή μπορείτε να χρησιμοποιήσετε κάποιο άλλο εργαλείο για τη διαχείριση βάσεων δεδομένων.

Ας ανοίξουμε το Adminer και ας δημιουργήσουμε μια νέα βάση δεδομένων με όνομα quickstart.

Δημιουργήστε έναν νέο πίνακα με το όνομα posts και προσθέστε αυτές τις στήλες:

  • id int, κάντε κλικ στο autoincrement (AI)
  • title varchar, μήκος 255
  • content text
  • created_at timestamp

Θα πρέπει να μοιάζει ως εξής:

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;

Είναι πολύ σημαντικό να χρησιμοποιείτε τον αποθηκευτικό χώρο του πίνακα InnoDB. Θα δείτε τον λόγο αργότερα. Προς το παρόν, απλά επιλέξτε αυτό και στείλτε το. Μπορείτε να πατήσετε Save τώρα.

Δοκιμάστε να προσθέσετε μερικές δειγματικές αναρτήσεις στο ιστολόγιο πριν υλοποιήσουμε τη δυνατότητα προσθήκης νέων αναρτήσεων απευθείας από την εφαρμογή μας.

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

Σύνδεση με τη βάση δεδομένων

Τώρα, όταν η βάση δεδομένων έχει δημιουργηθεί και έχουμε κάποιες αναρτήσεις σε αυτήν, είναι η κατάλληλη στιγμή να τις εμφανίσουμε στη νέα μας λαμπερή σελίδα.

Πρώτα, πρέπει να πούμε στην εφαρμογή μας ποια βάση δεδομένων θα χρησιμοποιήσει. Η ρύθμιση της σύνδεσης με τη βάση δεδομένων αποθηκεύεται στο config/common.neon. Ορίστε τη σύνδεση DSN και τα διαπιστευτήριά σας. Θα πρέπει να μοιάζει κάπως έτσι:

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

Προσέξτε τις εσοχές κατά την επεξεργασία αυτού του αρχείου. Η μορφή NEON δέχεται τόσο κενά όσο και ταμπέλες, αλλά όχι και τα δύο μαζί! Το αρχείο ρυθμίσεων στο Web Project χρησιμοποιεί τα tabs ως προεπιλογή.

Εισαγωγή της σύνδεσης της βάσης δεδομένων

Ο παρουσιαστής HomePresenter, ο οποίος θα απαριθμεί τα άρθρα, χρειάζεται μια σύνδεση με τη βάση δεδομένων. Για να τη λάβει, γράψτε έναν κατασκευαστή όπως αυτός:

<?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,
	) {
	}

	// ...
}

Φόρτωση αναρτήσεων από τη βάση δεδομένων

Τώρα ας φέρουμε τις αναρτήσεις από τη βάση δεδομένων και ας τις περάσουμε στο πρότυπο, το οποίο στη συνέχεια θα αποδώσει τον κώδικα HTML. Γι' αυτό το σκοπό υπάρχει η λεγόμενη μέθοδος render:

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

Ο παρουσιαστής έχει τώρα μια μέθοδο render renderDefault() που περνάει τα δεδομένα σε μια προβολή που ονομάζεται default. Τα πρότυπα του παρουσιαστή μπορούν να βρεθούν στο app/Presenters/templates/{PresenterName}/{viewName}.latte, οπότε σε αυτή την περίπτωση το πρότυπο θα βρίσκεται στο app/Presenters/templates/Home/default.latte. Στο πρότυπο, μια μεταβλητή με το όνομα $posts είναι τώρα διαθέσιμη, η οποία περιέχει τις δημοσιεύσεις από τη βάση δεδομένων.

Πρότυπο

Υπάρχει ένα γενικό πρότυπο για ολόκληρη τη σελίδα (που ονομάζεται layout, με κεφαλίδα, φύλλα στυλ, υποσέλιδο, …) και στη συνέχεια ειδικά πρότυπα για κάθε προβολή (π.χ. για την εμφάνιση της λίστας των αναρτήσεων του ιστολογίου), τα οποία μπορούν να παρακάμψουν ορισμένα τμήματα του προτύπου layout.

Από προεπιλογή, το πρότυπο διάταξης βρίσκεται στο templates/@layout.latte, το οποίο περιέχει:

...
{include content}
...

{include content} εισάγει ένα μπλοκ με το όνομα content στο κύριο πρότυπο. Μπορείτε να το ορίσετε στα πρότυπα κάθε προβολής. Σε αυτή την περίπτωση, θα επεξεργαστούμε το αρχείο Home/default.latte ως εξής:

{block content}
	Hello World
{/block}

Ορίζει το μπλοκπεριεχόμενο, το οποίο θα εισαχθεί στη διάταξη. Αν ανανεώσετε το πρόγραμμα περιήγησης, θα δείτε μια σελίδα με το κείμενο „Hello world“ (στον πηγαίο κώδικα επίσης με HTML κεφαλίδα και υποσέλιδο που ορίζονται στο @layout.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}

Αν ανανεώσετε το πρόγραμμα περιήγησής σας, θα δείτε τη λίστα με τις αναρτήσεις του ιστολογίου σας. Η λίστα δεν είναι πολύ φανταχτερή ή πολύχρωμη, γι' αυτό μη διστάσετε να προσθέσετε κάποιο λαμπερό CSS στο www/css/style.css και να το συνδέσετε σε μια διάταξη:

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

Η ετικέτα {foreach} επαναλαμβάνει όλες τις δημοσιεύσεις που έχουν περάσει στο πρότυπο στη μεταβλητή $posts και εμφανίζει ένα κομμάτι κώδικα HTML για κάθε δημοσίευση. Ακριβώς όπως θα έκανε ένας κώδικας PHP.

Το |date ονομάζεται φίλτρο. Τα φίλτρα χρησιμοποιούνται για τη μορφοποίηση της εξόδου. Το συγκεκριμένο φίλτρο μετατρέπει μια ημερομηνία (π.χ. 2013-04-12) στην πιο ευανάγνωστη μορφή της (12. 4. 2013). Το φίλτρο |truncate περικόπτει τη συμβολοσειρά στο καθορισμένο μέγιστο μήκος και προσθέτει μια έλλειψη στο τέλος, αν η συμβολοσειρά είναι περικομμένη. Δεδομένου ότι πρόκειται για προεπισκόπηση, δεν υπάρχει λόγος να εμφανιστεί το πλήρες περιεχόμενο του άρθρου. Άλλα προεπιλεγμένα φίλτρα μπορείτε να βρείτε στην τεκμηρίωση ή μπορείτε να δημιουργήσετε τα δικά σας αν χρειάζεται.

Και κάτι ακόμα. Μπορούμε να κάνουμε τον κώδικα λίγο πιο σύντομο και συνεπώς πιο απλό. Μπορούμε να αντικαταστήσουμε τα Latte tags με n:attributes όπως παρακάτω:

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

Το n:foreach, απλά τυλίγει το div με ένα μπλοκ foreach (κάνει ακριβώς το ίδιο πράγμα με το προηγούμενο μπλοκ κώδικα).

Περίληψη

Έχουμε μια πολύ απλή βάση δεδομένων MySQL με μερικές αναρτήσεις σε ιστολόγια. Η εφαρμογή συνδέεται με τη βάση δεδομένων και εμφανίζει μια απλή λίστα με τις αναρτήσεις.