-
-
Notifications
You must be signed in to change notification settings - Fork 277
Expand file tree
/
Copy pathcomments.texy
More file actions
171 lines (117 loc) · 7.57 KB
/
comments.texy
File metadata and controls
171 lines (117 loc) · 7.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
Komentarji
**********
Blog smo naložili na spletni strežnik in z uporabo Adminerja objavili nekaj zelo zanimivih prispevkov. Ljudje berejo naš blog in so nad njim zelo navdušeni. Vsak dan prejemamo veliko e-poštnih sporočil s pohvalami. Toda kaj nam pomaga vsa ta pohvala, če jo imamo samo v e-pošti in je nihče ne more prebrati? Bolje bi bilo, če bi bralec lahko neposredno komentiral članek, tako da bi lahko vsak prebral, kako čudoviti smo.
Torej, programirajmo komentarje.
Ustvarjanje nove tabele
=======================
Zaženimo Adminer in ustvarimo tabelo `comments` z naslednjimi stolpci:
- `id` int, označimo autoincrement (AI)
- `post_id`, tuji ključ, ki se nanaša na tabelo `posts`
- `name` varchar, length 255
- `email` varchar, length 255
- `content` text
- `created_at` timestamp
Tabela bi torej morala izgledati nekako takole:
[* adminer-comments.webp *]
Ne pozabite ponovno uporabiti shrambe InnoDB.
```sql
CREATE TABLE `comments` (
`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
`post_id` int(11) NOT NULL,
`name` varchar(250) NOT NULL,
`email` varchar(250) NOT NULL,
`content` text NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`)
) ENGINE=InnoDB CHARSET=utf8;
```
Obrazec za komentiranje
=======================
Najprej moramo ustvariti obrazec, ki bo uporabnikom omogočal komentiranje prispevkov. Nette Framework ima odlično podporo za obrazce. Lahko jih konfiguriramo v presenterju in izrišemo v predlogi.
Nette Framework uporablja koncept *komponent*. **Komponenta** je ponovno uporabljiv razred ali del kode, ki ga je mogoče priložiti drugi komponenti. Celo presenter je komponenta. Vsaka komponenta je ustvarjena preko tovarne. Torej bomo ustvarili tovarno za obrazec za komentarje v presenterju `PostPresenter`.
```php .{file:app/Presentation/Post/PostPresenter.php}
protected function createComponentCommentForm(): Form
{
$form = new Form; // pomeni Nette\Application\UI\Form
$form->addText('name', 'Ime:')
->setRequired();
$form->addEmail('email', 'E-pošta:');
$form->addTextArea('content', 'Komentar:')
->setRequired();
$form->addSubmit('send', 'Objavi komentar');
return $form;
}
```
Pojasnimo si to malo bolje. Prva vrstica ustvari novo instanco komponente `Form`. Naslednje metode priključijo HTML vnose v definicijo tega obrazca. `->addText` se bo izrisal kot `<input type="text" name="name">` z `<label>Ime:</label>`. Kot verjetno že pravilno ugibate, se `->addTextArea` izriše kot `<textarea>` in `->addSubmit` kot `<input type="submit">`. Obstaja še veliko podobnih metod, vendar te zaenkrat za ta obrazec zadostujejo. Več si lahko [preberete v dokumentaciji|forms:].
Če je obrazec že definiran v presenterju, ga lahko izrišemo (prikažemo) v predlogi. To storimo tako, da na konec predloge, ki izrisuje en konkreten prispevek, v `Post/show.latte` postavimo oznako `{control}`. Ker se komponenta imenuje `commentForm` (ime izhaja iz imena metode `createComponentCommentForm`), bo oznaka izgledala takole:
```latte .{file:app/Presentation/Post/show.latte}
...
<h2>Vnesite nov komentar</h2>
{control commentForm}
```
Če si zdaj ogledate stran s podrobnostmi prispevka, boste na njenem koncu videli nov obrazec za komentarje.
Shranjevanje v podatkovno bazo
==============================
Ste že poskusili izpolniti obrazec in ga poslati? Verjetno ste opazili, da obrazec pravzaprav nič ne naredi. Povezati moramo callback metodo, ki bo shranila poslana podatke.
Na vrstico pred `return` v tovarni za komponento `commentForm` postavimo naslednjo vrstico:
```php
$form->onSuccess[] = $this->commentFormSucceeded(...);
```
Prejšnji zapis pomeni "po uspešnem pošiljanju obrazca pokliči metodo `commentFormSucceeded` iz trenutnega presenterja". Ta metoda pa še ne obstaja. Ustvarimo jo torej:
```php .{file:app/Presentation/Post/PostPresenter.php}
private function commentFormSucceeded(\stdClass $data): void
{
$id = $this->getParameter('id');
$this->database->table('comments')->insert([
'post_id' => $id,
'name' => $data->name,
'email' => $data->email,
'content' => $data->content,
]);
$this->flashMessage('Hvala za komentar', 'success');
$this->redirect('this');
}
```
To metodo postavimo neposredno za tovarno obrazca `commentForm`.
Ta nova metoda ima en argument, ki je instanca obrazca, ki je bil poslan - ustvarjen s tovarno. Poslane vrednosti dobimo v `$data`. Nato shranimo podatke v podatkovno tabelo `comments`.
Tu sta še dve metodi, ki si zaslužita pojasnilo. Metoda `redirect` dobesedno preusmeri nazaj na trenutno stran. To je primerno storiti po vsakem pošiljanju obrazca, če je vseboval veljavne podatke in je callback izvedel operacijo, kot je bilo predvideno. Prav tako, če stran preusmerimo po pošiljanju obrazca, ne bomo videli dobro znanega sporočila `Želite ponovno poslati podatke iz obrazca?`, ki ga včasih lahko vidimo v brskalniku. (Na splošno velja, da bi po pošiljanju obrazca z metodo `POST` vedno morala slediti preusmeritev na `GET` akcijo.)
Metoda `flashMessage` je namenjena obveščanju uporabnika o rezultatu neke operacije. Ker preusmerjamo, sporočila ni mogoče preprosto predati predlogi in ga izrisati. Zato je tu ta metoda, ki si to sporočilo shrani in ga naredi dostopnega ob naslednjem nalaganju strani. Flash sporočila se izrisujejo v glavni predlogi `app/Presentation/@layout.latte` in izgledajo takole:
```latte
<div n:foreach="$flashes as $flash" n:class="flash, $flash->type">
{$flash->message}
</div>
```
Kot že vemo, se flash sporočila samodejno predajo predlogi, zato o tem ni treba veliko razmišljati, preprosto deluje. Za več informacij [obiščite dokumentacijo |application:presenters#Flash sporočila].
Izrisovanje komentarjev
=======================
To je ena tistih stvari, ki jih boste preprosto vzljubili. Nette Database ima odlično funkcijo imenovano [Explorer |database:explorer]. Se še spomnite, da smo tabele v podatkovni bazi namenoma ustvarjali z InnoDB shrambo? Adminer je tako ustvaril nekaj, čemur se reče [tuji ključi |https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html], ki nam bodo prihranili veliko dela.
Nette Database Explorer uporablja tuje ključe za reševanje medsebojnih odnosov med tabelami in na podlagi poznavanja teh odnosov zna samodejno ustvariti podatkovne poizvedbe.
Kot se zagotovo spomnite, smo v predlogo predali spremenljivko `$post` z metodo `PostPresenter::renderShow()` in zdaj želimo iterirati skozi vse komentarje, ki imajo vrednost stolpca `post_id` enako `$post->id`. To lahko dosežemo s klicem `$post->related('comments')`. Da, tako preprosto. Poglejmo si končno kodo:
```php .{file:app/Presentation/Post/PostPresenter.php}
public function renderShow(int $id): void
{
...
$this->template->post = $post;
$this->template->comments = $post->related('comments')->order('created_at');
}
```
In predlogo:
```latte .{file:app/Presentation/Post/show.latte}
...
<h2>Komentarji</h2>
<div class="comments">
{foreach $comments as $comment}
<p><b><a href="mailto:{$comment->email}" n:tag-if="$comment->email">
{$comment->name}
</a></b> napisal:</p>
<div>{$comment->content}</div>
{/foreach}
</div>
...
```
Opazite poseben atribut `n:tag-if`. Že veste, kako delujejo `n:atributi`. Če atributu dodate predpono `tag-`, se funkcionalnost uporabi samo za HTML oznako, ne pa za njeno vsebino. To nam omogoča, da iz imena komentatorja naredimo povezavo samo v primeru, da je navedel svoj e-poštni naslov. Ti dve vrstici sta identični:
```latte
<strong n:tag-if="$important"> Dober dan! </strong>
{if $important}<strong>{/if} Dober dan! {if $important}</strong>{/if}
```
{{priority: -1}}