Blog Ana Sayfası
****************
.[perex]
Son gönderilerinizi gösteren ana sayfayı oluşturalım.
Başlamadan önce, Model-View-Presenter tasarım deseni (MVC((Model-View-Controller)) desenine benzer) hakkında en azından bazı temelleri bilmelisiniz:
- **Model** - veriyle çalışan katman. Uygulamanın geri kalanından tümüyle ayrıdır. Yalnızca presenter'la iletişim kurar.
- **View** - ön uç katmanı. İstenen veriyi şablonlar kullanarak render eder ve kullanıcıya gösterir.
- **Presenter** (ya da Controller) - bağlantı katmanı. Presenter, Model ile View'ı birbirine bağlar. İstekleri ele alır, Model'den veri ister ve sonra onları View'a aktarır.
Bizim blogumuz gibi basit bir uygulamada model katmanının tamamı yalnızca veritabanı sorgularından oluşacak; bunun için henüz fazladan PHP koduna ihtiyacımız yok. Yani başlangıçta yalnızca presenter'ları ve şablonları oluşturacağız. Nette'de her presenter'ın kendi şablonları vardır, dolayısıyla onları aynı anda oluşturacağız.
Adminer ile Veritabanı Oluşturma
================================
Veriyi saklamak için MySQL veritabanını kullanacağız; çünkü web geliştiricileri arasında en yaygın seçim odur. Ancak onu kullanmak istemiyorsanız istediğiniz veritabanını seçmekten çekinmeyin.
Blog gönderilerimizi saklayacak veritabanı yapısını hazırlayalım. Çok basit başlayabiliriz; yalnızca gönderiler için tek bir tabloyla.
Veritabanını oluşturmak için [Adminer |https://www.adminer.org] aracını indirebilir ya da yeğlediğiniz başka bir veritabanı yönetim aracını kullanabiliriz.
Adminer'ı açalım ve `quickstart` adında yeni bir veritabanı oluşturalım.
`posts` adında yeni bir tablo oluşturun ve şu sütunları ekleyin:
- `id` int, autoincrement (AI) işaretli
- `title` varchar, uzunluk 255
- `content` text
- `created_at` timestamp
Şöyle görünmelidir:
[* 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** depolama motorunu kullanmak çok önemlidir. Nedenini sonra göreceksiniz. Şimdilik yalnızca onu seçip Kaydet'e tıklayın.
Yeni gönderi eklemeyi doğrudan uygulamamızdan gerçekleştirmeden önce, birkaç örnek blog gönderisini elle eklemeyi deneyin.
```sql
INSERT INTO `posts` (`id`, `title`, `content`, `created_at`) VALUES
(1, 'Article One', 'Lorem ipsum dolor one', CURRENT_TIMESTAMP),
(2, 'Article Two', 'Lorem ipsum dolor two', CURRENT_TIMESTAMP),
(3, 'Article Three', 'Lorem ipsum dolor three', CURRENT_TIMESTAMP);
```
Veritabanına Bağlanma
=====================
Veritabanı oluşturulduğuna ve içinde birkaç gönderi bulunduğuna göre, onları yepyeni sayfamızda göstermenin tam zamanı.
Önce uygulamamıza hangi veritabanını kullanacağını söylememiz gerekiyor. Veritabanı bağlantısı yapılandırması, `config/common.neon` dosyasında DSN((Data Source Name)) ve kimlik bilgileriyle ayarlanır. Şuna benzer görünmelidir:
```neon .{file:config/common.neon}
database:
dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
user: *kullanıcı adınızı buraya girin*
password: *veritabanı parolanızı buraya girin*
```
.[note]
Bu dosyayı düzenlerken girintiye dikkat edin. [NEON biçimi |neon:format] hem boşlukları hem sekmeleri kabul eder, ama ikisini bir arada kabul etmez. Web Project'teki varsayılan yapılandırma dosyası sekme kullanır.
Veritabanı Bağlantısını Enjekte Etme
====================================
Gönderileri listeleyecek olan `HomePresenter` presenter'ının bir veritabanı bağlantısına ihtiyacı var. Onu almak için yapıcıyı şöyle kullanacağız:
```php .{file:app/Presentation/Home/HomePresenter.php}
<?php
namespace App\Presentation\Home;
use Nette;
final class HomePresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private Nette\Database\Explorer $database,
) {
}
// ...
}
```
Gönderileri Veritabanından Yükleme
==================================
Şimdi gönderileri veritabanından getirip, HTML kodunu render edecek şablona aktaralım. *render* metodu denen şey tam da bunun içindir:
```php .{file:app/Presentation/Home/HomePresenter.php}
public function renderDefault(): void
{
$this->template->posts = $this->database
->table('posts')
->order('created_at DESC')
->limit(5);
}
```
Presenter'ın artık, veritabanından gelen veriyi şablona (View) aktaran bir `renderDefault()` render metodu var. Şablonlar `app/Presentation/{PresenterAdı}/{viewAdı}.latte` konumunda bulunur, dolayısıyla bu durumda şablon `app/Presentation/Home/default.latte` dosyasındadır. Şablonda artık, veritabanından getirilen gönderileri içeren `$posts` adlı bir değişken kullanılabilir.
Şablon
======
Tüm web sitesi için bir ana şablonumuz (*layout* denir; başlığı, stilleri, alt bilgiyi vb. içerir) ve her view için, ana şablonun parçalarını geçersiz kılabilen özel şablonlar (örneğin blog gönderilerini göstermek için) vardır.
Yerleşim şablonu varsayılan olarak `app/Presentation/@layout.latte` dosyasında bulunur ve şunu içerir:
```latte .{file:app/Presentation/@layout.latte}
...
{include content}
...
```
`{include content}` etiketi, ana şablona `content` adlı bir blok ekler. Bu bloğu tek tek view'ların şablonlarında tanımlayacağız. Bizim durumumuzda `Home/default.latte` dosyasını şöyle değiştireceğiz:
```latte .{file:app/Presentation/Home/default.latte}
{block content}
Hello World
{/block}
```
Bu, ana yerleşime eklenecek *content* [bloğunu |latte:tags#{block}] tanımlar. Tarayıcıyı yeniden yenilerseniz, "Hello World" metnini içeren bir sayfa göreceksiniz (kaynak kodda, `@layout.latte` dosyasında tanımlı HTML başlığı ve alt bilgisiyle birlikte).
Blog gönderilerini gösterelim; şablonu şöyle değiştireceğiz:
```latte .{file:app/Presentation/Home/default.latte}
{block content}
<h1>Blogum</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}
```
Tarayıcınızı yenilerseniz blog gönderilerinizin listesini göreceksiniz. Liste henüz pek şık ya da renkli değil, bu yüzden `www/css/style.css` dosyasına [güzel CSS stilleri |https://github.com/nette-examples/quickstart/blob/v4.0/www/css/style.css] eklemekten ve onu yerleşimde bağlamaktan çekinmeyin:
```latte .{file:app/Presentation/@layout.latte}
...
<link rel="stylesheet" href="{$basePath}/css/style.css">
</head>
...
```
`{foreach}` etiketi, şablona `$posts` değişkeniyle aktarılan tüm gönderileri dolaşır ve her gönderi için bir HTML kodu parçası gösterir. Tıpkı PHP kodu gibi davranır.
`|date:` yazımına filtre denir. Filtreler çıktıyı biçimlendirmek için kullanılır. Bu filtre, bir tarihi (örneğin `2013-04-12`) daha okunur bir biçime (`April 12, 2013`) dönüştürür. `|truncate` filtresi, dizeyi belirtilen en fazla uzunluğa kısaltır ve dize kısaltıldıysa sonuna üç nokta (...) ekler. Bu bir önizleme olduğundan, gönderinin içeriğinin tamamını göstermenin anlamı yok. Diğer varsayılan filtreler [belgelerde bulunabilir |latte:filters]; ya da gerekiyorsa kendinizinkini yazabilirsiniz.
Bir şey daha. Önceki kodu daha kısa ve basit kılabiliriz. Bunu, *Latte etiketlerini* *n:attribute*'larla değiştirerek başarırız:
```latte .{file:app/Presentation/Home/default.latte}
{block content}
<h1>Blogum</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}
```
`n:foreach` niteliği, *div* bloğunu bir *foreach* döngüsüyle sarar (tam olarak önceki kodla aynı şekilde çalışır).
Özet
====
Artık birkaç gönderi içeren çok basit bir MySQL veritabanımız var. Uygulama bu veritabanına bağlanıyor ve bu gönderilerin basit bir listesini bir şablonda gösteriyor.
{{priority: -1}}
Blog Ana Sayfası
Son gönderilerinizi gösteren ana sayfayı oluşturalım.
Başlamadan önce, Model-View-Presenter tasarım deseni (MVC desenine
benzer) hakkında en azından bazı temelleri bilmelisiniz:
Model – veriyle çalışan katman. Uygulamanın geri kalanından tümüyle ayrıdır. Yalnızca presenter'la
iletişim kurar.
View – ön uç katmanı. İstenen veriyi şablonlar kullanarak render eder ve kullanıcıya gösterir.
Presenter (ya da Controller) – bağlantı katmanı. Presenter, Model ile View'ı birbirine bağlar. İstekleri ele
alır, Model'den veri ister ve sonra onları View'a aktarır.
Bizim blogumuz gibi basit bir uygulamada model katmanının tamamı yalnızca veritabanı sorgularından oluşacak; bunun için
henüz fazladan PHP koduna ihtiyacımız yok. Yani başlangıçta yalnızca presenter'ları ve şablonları oluşturacağız.
Nette'de her presenter'ın kendi şablonları vardır, dolayısıyla onları aynı anda oluşturacağız.
Adminer ile Veritabanı Oluşturma
Veriyi saklamak için MySQL veritabanını kullanacağız; çünkü web geliştiricileri arasında en yaygın seçim odur.
Ancak onu kullanmak istemiyorsanız istediğiniz veritabanını seçmekten çekinmeyin.
Blog gönderilerimizi saklayacak veritabanı yapısını hazırlayalım. Çok basit başlayabiliriz; yalnızca gönderiler
için tek bir tabloyla.
Veritabanını oluşturmak için Adminer aracını indirebilir ya da yeğlediğiniz
başka bir veritabanı yönetim aracını kullanabiliriz.
Adminer'ı açalım ve quickstart adında yeni bir veritabanı oluşturalım.
posts adında yeni bir tablo oluşturun ve şu sütunları ekleyin:
id int, autoincrement (AI) işaretli
title varchar, uzunluk 255
content text
created_at timestamp
Şöyle görünmelidir:
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 depolama motorunu kullanmak çok önemlidir. Nedenini sonra göreceksiniz. Şimdilik yalnızca
onu seçip Kaydet'e tıklayın.
Yeni gönderi eklemeyi doğrudan uygulamamızdan gerçekleştirmeden önce, birkaç örnek blog gönderisini elle eklemeyi
deneyin.
INSERT INTO `posts` (`id`, `title`, `content`, `created_at`) VALUES
(1, 'Article One', 'Lorem ipsum dolor one', CURRENT_TIMESTAMP),
(2, 'Article Two', 'Lorem ipsum dolor two', CURRENT_TIMESTAMP),
(3, 'Article Three', 'Lorem ipsum dolor three', CURRENT_TIMESTAMP);
Veritabanına Bağlanma
Veritabanı oluşturulduğuna ve içinde birkaç gönderi bulunduğuna göre, onları yepyeni sayfamızda göstermenin tam
zamanı.
Önce uygulamamıza hangi veritabanını kullanacağını söylememiz gerekiyor. Veritabanı bağlantısı yapılandırması,
config/common.neon dosyasında DSN ve kimlik bilgileriyle
ayarlanır. Şuna benzer görünmelidir:
database:
dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
user: *kullanıcı adınızı buraya girin*
password: *veritabanı parolanızı buraya girin*
Bu dosyayı düzenlerken girintiye dikkat edin. NEON biçimi hem
boşlukları hem sekmeleri kabul eder, ama ikisini bir arada kabul etmez. Web Project'teki varsayılan yapılandırma dosyası
sekme kullanır.
Veritabanı Bağlantısını Enjekte Etme
Gönderileri listeleyecek olan HomePresenter presenter'ının bir veritabanı bağlantısına ihtiyacı var. Onu
almak için yapıcıyı şöyle kullanacağız:
<?php
namespace App\Presentation\Home;
use Nette;
final class HomePresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private Nette\Database\Explorer $database,
) {
}
// ...
}
Gönderileri Veritabanından Yükleme
Şimdi gönderileri veritabanından getirip, HTML kodunu render edecek şablona aktaralım. render metodu denen şey tam
da bunun içindir:
public function renderDefault(): void
{
$this->template->posts = $this->database
->table('posts')
->order('created_at DESC')
->limit(5);
}
Presenter'ın artık, veritabanından gelen veriyi şablona (View) aktaran bir renderDefault() render metodu var.
Şablonlar app/Presentation/{PresenterAdı}/{viewAdı}.latte konumunda bulunur, dolayısıyla bu durumda şablon
app/Presentation/Home/default.latte dosyasındadır. Şablonda artık, veritabanından getirilen gönderileri içeren
$posts adlı bir değişken kullanılabilir.
Şablon
Tüm web sitesi için bir ana şablonumuz (layout denir; başlığı, stilleri, alt bilgiyi vb. içerir) ve her view
için, ana şablonun parçalarını geçersiz kılabilen özel şablonlar (örneğin blog gönderilerini göstermek için)
vardır.
Yerleşim şablonu varsayılan olarak app/Presentation/@layout.latte dosyasında bulunur ve şunu içerir:
...
{include content}
...
{include content} etiketi, ana şablona content adlı bir blok ekler. Bu bloğu tek tek view'ların
şablonlarında tanımlayacağız. Bizim durumumuzda Home/default.latte dosyasını şöyle değiştireceğiz:
{block content}
Hello World
{/block}
Bu, ana yerleşime eklenecek contentbloğunu tanımlar.
Tarayıcıyı yeniden yenilerseniz, “Hello World” metnini içeren bir sayfa göreceksiniz (kaynak kodda,
@layout.latte dosyasında tanımlı HTML başlığı ve alt bilgisiyle birlikte).
Blog gönderilerini gösterelim; şablonu şöyle değiştireceğiz:
Tarayıcınızı yenilerseniz blog gönderilerinizin listesini göreceksiniz. Liste henüz pek şık ya da renkli değil, bu
yüzden www/css/style.css dosyasına güzel CSS stilleri eklemekten ve onu
yerleşimde bağlamaktan çekinmeyin:
{foreach} etiketi, şablona $posts değişkeniyle aktarılan tüm gönderileri dolaşır ve her
gönderi için bir HTML kodu parçası gösterir. Tıpkı PHP kodu gibi davranır.
|date: yazımına filtre denir. Filtreler çıktıyı biçimlendirmek için kullanılır. Bu filtre, bir tarihi
(örneğin 2013-04-12) daha okunur bir biçime (April 12, 2013) dönüştürür. |truncate
filtresi, dizeyi belirtilen en fazla uzunluğa kısaltır ve dize kısaltıldıysa sonuna üç nokta (…) ekler. Bu bir önizleme
olduğundan, gönderinin içeriğinin tamamını göstermenin anlamı yok. Diğer varsayılan filtreler belgelerde bulunabilir; ya da gerekiyorsa kendinizinkini yazabilirsiniz.
Bir şey daha. Önceki kodu daha kısa ve basit kılabiliriz. Bunu, Latte etiketlerinin:attribute'larla
değiştirerek başarırız:
n:foreach niteliği, div bloğunu bir foreach döngüsüyle sarar (tam olarak önceki kodla aynı
şekilde çalışır).
Özet
Artık birkaç gönderi içeren çok basit bir MySQL veritabanımız var. Uygulama bu veritabanına bağlanıyor ve bu
gönderilerin basit bir listesini bir şablonda gösteriyor.