Nette Documentation Preview

syntax
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 content bloğ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:

{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 eklemekten ve onu yerleşimde bağlamaktan çekinmeyin:

	...
	<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; 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:

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