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 tabeloposts
name
varchar, length 255email
varchar, length 255content
textcreated_at
timestamp
Tabela bi torej morala izgledati nekako takole:

Ne pozabite ponovno uporabiti shrambe InnoDB.
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
.
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.
Č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:
...
<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:
$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:
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:
<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.
Izrisovanje komentarjev
To je ena tistih stvari, ki jih boste preprosto vzljubili. Nette Database ima odlično funkcijo imenovano 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, 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:
public function renderShow(int $id): void
{
...
$this->template->post = $post;
$this->template->comments = $post->related('comments')->order('created_at');
}
In predlogo:
...
<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:
<strong n:tag-if="$important"> Dober dan! </strong>
{if $important}<strong>{/if} Dober dan! {if $important}</strong>{/if}