# Blade şablon motoru: tekrar eden HTML'i bitirmek

> Görünüm katmanını mantıktan ayırmanın pratik kazancı: Blade layout, section ve partial kullanımı.

- Yayın: 2014-07-06
- Kategori: Framework & Kütüphane
- Etiketler: Laravel
- Okuma süresi: 3 dk okuma
- Kaynak: https://www.muhammetsafak.com.tr/blog/blade-sablon-motoru-tekrar-eden-htmli-bitirmek/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
[Laravel'de](/blog/laravel-4-ile-ilk-projeme-baslarken) çalışmaya devam ediyorum. Bu ay görünüm katmanına odaklandım. Daha önce PHP şablonlarında yaptığım şey şuydu: her sayfada `header.php` ve `footer.php` dahil etmek. Küçük projelerde idare eder ama büyüdükçe hangi sayfanın neyi dahil ettiğini takip etmek güçleşiyor.

**Blade**, Laravel'in şablon motorudur. Saf PHP şablonlarından farklı olarak template inheritance ve partial'lar için temiz bir sözdizimi sunar.

## Neden şablon motoru?

Ham PHP şablonlarında HTML ile PHP kodu iç içe giriyor. Uzun bir sayfada `<?php foreach(...): ?>` ile `<?php endforeach; ?>` arasında kaybolmak kolay. Blade bunu `@foreach` ve `@endforeach` gibi direktiflerle daha okunabilir yapıyor. Ayrıca çıktıyı otomatik olarak XSS'e (Siteler Arası Betik Çalıştırma — Cross-Site Scripting) karşı kaçıyor.

Eski yöntemde `<?= $kullanici->ad ?>` yazdığımda XSS koruması yoktu; kullanıcıdan gelen veriyi ekrana basıyordum. Blade'in `{{ $kullanici->ad }}` sözdizimi otomatik olarak `htmlspecialchars()` çağırıyor — bu güvenliği varsayılan hale getiriyor.

## Ana düzen (layout) oluşturmak

Önce temel iskelet olan düzen dosyasını oluşturuyorum: `app/views/layouts/ana.blade.php`

```html
<!DOCTYPE html>
<html>
<head>
    <title>@yield('baslik') | Sitem</title>
    <link rel="stylesheet" href="/css/uygulama.css">
</head>
<body>
    @include('partials.menu')

    <div class="icerik">
        @yield('icerik')
    </div>

    @include('partials.altbilgi')
</body>
</html>
```

`@yield('icerik')`, çocuk sayfaların kendi içeriklerini buraya enjekte edebileceği bir yer tutucu tanımlar. `@include` ile tekrar eden bölümleri ayrı dosyalara taşıyorum.

## Çocuk görünüm

`app/views/anasayfa.blade.php`:

```html
@extends('layouts.ana')

@section('baslik', 'Ana Sayfa')

@section('icerik')
    <h1>Hoş geldiniz</h1>
    <p>Bu sitenin ana sayfasıdır.</p>

    @foreach($haberler as $haber)
        <div class="haber">
            <h2>{{ $haber->baslik }}</h2>
            <p>{{ $haber->ozet }}</p>
        </div>
    @endforeach
@endsection
```

`@extends('layouts.ana')` hangi düzeni kullandığını bildirir. `@section` ile o düzendeki `@yield` alanlarını dolduruyorsunuz. `{{ $degisken }}` sözdizimi HTML özel karakterlerini kaçırarak güvenli çıktı üretir.

## Koşullar ve döngüler

Blade direktifleri saf PHP eşdeğerleriyle birebir örtüşüyor:

```html
@if($kullanici->girisYapti())
    <a href="/cikis">Çıkış</a>
@else
    <a href="/giris">Giriş</a>
@endif

@forelse($yorumlar as $yorum)
    <p>{{ $yorum->metin }}</p>
@empty
    <p>Henüz yorum yok.</p>
@endforelse
```

`@forelse`, liste boşken `@empty` bloğunu gösterir. Bu kombinasyonu çok sık kullanıyorum; eskiden `count($dizi) > 0` kontrolü ayrıca yazardım.

## Kısmi görünümler (partials)

Tekrar eden parçaları ayrı dosyalara taşımak düzeni koruyor. Menüyü `app/views/partials/menu.blade.php` dosyasına koyuyorum:

```html
<nav>
    <a href="/">Ana Sayfa</a>
    <a href="/hakkimda">Hakkımda</a>
    @if(Auth::check())
        <a href="/panel">Panel</a>
    @endif
</nav>
```

Her sayfada `@include('partials.menu')` yazıyorum, gerisini Blade hallediyor.

## Denetleyiciden görünüme veri aktarmak

Denetleyicide (controller) değişkeni görünüme aktarmanın birkaç yolu var:

```php
// compact() ile
$haberler = Haber::all();
return View::make('anasayfa', compact('haberler'));

// with() ile zincir
return View::make('anasayfa')->with('haberler', Haber::all());
```

Her ikisi de aynı sonucu veriyor; `compact()` birden fazla değişken varken daha pratik.

## PHP ifadesi çalıştırmak

Zaman zaman Blade direktifi olmayan PHP'ye ihtiyaç duyulabiliyor. `@php` ile blok açılabilir:

```html
@php
    $toplam = $fiyat * $adet;
@endphp

<p>Toplam: {{ $toplam }} TL</p>
```

Bunu nadiren kullanıyorum; iş mantığı görünüm katmanına girmemeli. Ama basit hesaplamalar için iş görüyor.

## Kaçış gerektiren durum: ham HTML basmak

Blade'in `{{ }}` sözdizimi her zaman HTML kaçışı yapıyor — bu iyi. Ama veritabanında HTML içerik saklanıyorsa ve onu olduğu gibi basmak gerekiyorsa `{!! !!}` sözdizimi kullanılıyor:

```html
{!! $makale->icerik !!}
```

Bunu yalnızca güvendiğiniz kaynaklardan gelen içerik için kullanmak gerekiyor. Kullanıcının girdiği veriyi `{!! !!}` ile basmak, XSS korumasını tamamen devre dışı bırakır. Bu ayrımı öğrendiğimde bir CMS projesinde görmüştüm: düzenleyiciden gelen HTML makaleler için `{!! !!}` doğruydu, ama yorum alanları için aynı sözdizimini kullansaydık güvenlik açığı çıkardı.

## Önceki yöntemle karşılaştırma

Eski `header.php` / `footer.php` yaklaşımında her sayfaya iki `include` yazıyordum ve her ikisinin de birbirine bağımlı olduğunu aklımda tutuyordum. Blade'in kalıtım modeli bunu tersine çeviriyor: merkezi düzen dosyası var, çocuk sayfalar ona bağlanıyor. Sayfa eklemek çok daha temiz.

Birkaç haftalık kullanımdan sonra şablon motorunun getirdiği düzeni beğendim. Özellikle `@forelse` ve `@include` kombinasyonu tekrar eden kodu belirgin şekilde azalttı. Bir de XSS korumasının varsayılan gelmesi, güvenliği her seferinde "hatırlanması gereken bir şey" olmaktan çıkarıyor.

Blade'in bir özelliği daha var: `@stack` ve `@push` direktifleriyle sayfaya özgü CSS veya JavaScript bloklarını düzen dosyasındaki belirli bir noktaya enjekte edebiliyorsunuz. Örneğin bir sayfa özel bir JavaScript kütüphanesi gerektiriyorsa, onu o sayfanın görünümünden düzenin `</body>` etiketinden önce tanımlanmış `@stack('scripts')` alanına gönderebilirsiniz. Tüm JS'i tek bir bundle'a koymak yerine, sayfaya özgü betiği sadece o sayfa yüklendiğinde dahil etmek bu yolla mümkün oluyor.
