Laravel’de Blade Kullanımı: Kod Örnekleriyle Rehber
Laravel Blade template motorunu layout, section, include, component, slot, directive, form, validation, auth ve güvenli çıktı örnekleriyle anlatıyorum.
Laravel Blade, Laravel’in view yani arayüz tarafında kullandığı template motorudur. Düz PHP ile HTML yazmak yerine daha okunabilir, daha düzenli ve tekrar kullanılabilir ekranlar hazırlamamızı sağlar. `@if`, `@foreach`, `@extends`, `@section`, `@csrf`, `@auth`, component ve slot gibi yapılar Blade’in günlük hayatta en çok kullanılan parçalarıdır.
Bu yazıda Blade kullanımını sıfırdan başlayıp gerçek projede lazım olacak seviyeye kadar anlatacağım. Türkçe’yi çok kusursuz akademik değil, geliştirici gözüyle anlaşılır tutuyorum. Kod örnekleri Laravel 12 mantığına uygundur.
Blade Nedir?
Blade, `resources/views` klasörü altında `.blade.php` uzantılı dosyalarla çalışır. Örneğin ana sayfa view dosyası şöyle olabilir:
resources/views/home.blade.php
Blade dosyaları aslında PHP’ye derlenir ve Laravel tarafından cache altında saklanır. Yani Blade özel bir frontend framework değildir. Server-side render edilen Laravel view yapısıdır.
1. İlk Blade View Oluşturma
Önce basit bir route yazalım. `routes/web.php`:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/blog', function () {
return view('blog.index', [
'title' => 'Laravel Blade Kullanımı',
'posts' => [
['title' => 'İlk Laravel Yazısı', 'slug' => 'ilk-laravel-yazisi'],
['title' => 'Blade Öğreniyorum', 'slug' => 'blade-ogreniyorum'],
],
]);
});
Bu route şu dosyayı çağırır:
resources/views/blog/index.blade.php
View dosyası:
<h1>{{ $title }}</h1>
<ul>
@foreach ($posts as $post)
<li>
<a href="/blog/{{ $post['slug'] }}">
{{ $post['title'] }}
</a>
</li>
@endforeach
</ul>
`{{ $title }}` veriyi güvenli şekilde ekrana basar. `@foreach` ise listeyi döndürür. Dikkat edersen PHP etiketi açmadık; Blade bunu bizim için sadeleştiriyor.
2. Güvenli Çıktı: {{ }} ve {!! !!}
Blade’de veri basmanın en güvenli yolu çift süslü parantezdir:
{{ $post->title }}
Bu kullanım HTML karakterlerini escape eder. Yani kullanıcı başlık içine zararlı script yazarsa direkt çalışmaz. Örnek:
<script>alert('xss')</script>
Bu veri `{{ }}` ile basılırsa tarayıcıda script olarak çalışmaz, metin gibi görünür.
Ham HTML basmak için şu kullanılır:
{!! $post->content !!}
Fakat bunu sadece güvendiğin, temizlenmiş içeriklerde kullan. Kullanıcıdan gelen yorumu, adı, başlığı ham HTML olarak basmak XSS açığı doğurabilir.
3. Koşullar: @if, @else, @unless
Blade içinde koşul yazmak için `@if` kullanılır:
@if ($post->is_published)
<span>Yayında</span>
@else
<span>Taslak</span>
@endif
`@unless`, koşul false ise çalışır:
@unless ($post->is_published)
<p>Bu yazı henüz yayında değil.</p>
@endunless
Değer var mı yok mu kontrolü için:
@isset($post->published_at)
<time>{{ $post->published_at->format('d.m.Y') }}</time>
@endisset
@empty($posts)
<p>Henüz blog yazısı yok.</p>
@endempty
4. Döngüler ve $loop Değişkeni
`@foreach` en çok kullanılan döngüdür:
@foreach ($posts as $post)
<article>
<h2>{{ $post->title }}</h2>
<p>{{ $post->excerpt }}</p>
</article>
@endforeach
Liste boşsa `@forelse` daha temizdir:
@forelse ($posts as $post)
<article>
<h2>{{ $post->title }}</h2>
</article>
@empty
<p>Henüz içerik eklenmedi.</p>
@endforelse
Blade döngülerinde `$loop` adında yardımcı değişken gelir:
@foreach ($posts as $post)
<div class="{{ $loop->first ? 'first-post' : '' }}">
<span>{{ $loop->iteration }}</span>
<h2>{{ $post->title }}</h2>
@if ($loop->last)
<small>Son yazı</small>
@endif
</div>
@endforeach
`$loop->first`, `$loop->last`, `$loop->iteration`, `$loop->index`, `$loop->count` gibi değerler özellikle kart listelerinde çok işe yarar.
5. Layout Mantığı: @extends, @section, @yield
Gerçek projede her sayfaya tekrar tekrar HTML iskeleti yazmayız. Bir ana layout oluştururuz.
`resources/views/layouts/app.blade.php`:
<!doctype html>
<html lang="tr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>@yield('title', config('app.name'))</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
<header>
<a href="/">{{ config('app.name') }}</a>
@include('partials.navigation')
</header>
<main>
@yield('content')
</main>
<footer>
<p>© {{ date('Y') }}</p>
</footer>
@stack('scripts')
</body>
</html>
Şimdi blog index sayfası bu layout’u kullansın.
`resources/views/blog/index.blade.php`:
@extends('layouts.app')
@section('title', 'Blog Yazıları')
@section('content')
<h1>Blog Yazıları</h1>
@foreach ($posts as $post)
<article>
<h2>{{ $post->title }}</h2>
<p>{{ $post->excerpt }}</p>
</article>
@endforeach
@endsection
`@extends` ana şablonu seçer. `@section` içerik gönderir. Layout içindeki `@yield('content')` o içeriği ekrana basar.
6. Partial Kullanımı: @include
Tekrar eden küçük parçalar için `@include` kullanılır. Örnek navigation:
resources/views/partials/navigation.blade.php
<nav>
<a href="/">Ana Sayfa</a>
<a href="/blog">Blog</a>
<a href="/iletisim">İletişim</a>
</nav>
Layout içinde çağırma:
@include('partials.navigation')
Partial’a veri göndermek de mümkündür:
@include('partials.post-card', ['post' => $post])
Fakat çok sık tekrar eden ve parametre alan parçalar için component daha düzenli olur.
7. Component Kullanımı
Laravel Blade component sistemi, arayüz parçalarını tekrar kullanılabilir hale getirir. Komutla component oluşturabilirsin:
php artisan make:component Alert
Bu komut genelde iki dosya oluşturur:
app/View/Components/Alert.php
resources/views/components/alert.blade.php
Basit component view örneği:
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $slot }}
</div>
Component class içinde varsayılan type:
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
public function __construct(
public string $type = 'info'
) {
}
public function render()
{
return view('components.alert');
}
}
Kullanım:
<x-alert type="success">
Kayıt başarıyla oluşturuldu.
</x-alert>
`$slot`, component içine yazılan içeriği temsil eder. `$attributes` ise component’e verilen HTML attribute değerlerini yönetir.
8. Anonymous Component
Her component için PHP class yazmak zorunda değilsin. Sadece Blade dosyasıyla anonymous component oluşturabilirsin.
`resources/views/components/badge.blade.php`:
@props([
'color' => 'gray',
])
<span {{ $attributes->merge(['class' => 'badge badge-'.$color]) }}>
{{ $slot }}
</span>
Kullanım:
<x-badge color="red">Laravel</x-badge>
<x-badge color="green">Yayında</x-badge>
Basit UI parçalarında anonymous component daha hızlı ve temizdir.
9. Slot ve Named Slot
Component içinde birden fazla içerik alanı gerekiyorsa named slot kullanılır.
`resources/views/components/card.blade.php`:
<div class="card">
@isset($title)
<div class="card-title">
{{ $title }}
</div>
@endisset
<div class="card-body">
{{ $slot }}
</div>
@isset($footer)
<div class="card-footer">
{{ $footer }}
</div>
@endisset
</div>
Kullanım:
<x-card>
<x-slot:title>
Laravel Blade Kartı
</x-slot:title>
<p>Bu alan kartın ana içeriğidir.</p>
<x-slot:footer>
<a href="/blog">Tüm yazılar</a>
</x-slot:footer>
</x-card>
Named slot, özellikle modal, card, panel, dashboard widget gibi yapılarda temiz bir çözüm sağlar.
10. Form Kullanımı: @csrf, old(), @error
Laravel formlarında CSRF koruması şarttır. Blade içinde `@csrf` bunu kolayca ekler.
<form method="POST" action="{{ route('posts.store') }}">
@csrf
<div>
<label for="title">Başlık</label>
<input id="title" type="text" name="title" value="{{ old('title') }}">
@error('title')
<p>{{ $message }}</p>
@enderror
</div>
<div>
<label for="content">İçerik</label>
<textarea id="content" name="content">{{ old('content') }}</textarea>
@error('content')
<p>{{ $message }}</p>
@enderror
</div>
<button type="submit">Kaydet</button>
</form>
`old('title')`, validation hatası sonrası kullanıcının yazdığı değeri tekrar forma koyar. `@error('title')` ilgili alanın hata mesajını gösterir.
11. PUT, PATCH, DELETE İçin @method
HTML formları doğal olarak sadece GET ve POST destekler. Laravel’de update veya delete işlemlerinde method spoofing kullanılır.
<form method="POST" action="{{ route('posts.update', $post) }}">
@csrf
@method('PUT')
<input type="text" name="title" value="{{ old('title', $post->title) }}">
<button type="submit">Güncelle</button>
</form>
Silme formu:
<form method="POST" action="{{ route('posts.destroy', $post) }}">
@csrf
@method('DELETE')
<button type="submit">Sil</button>
</form>
12. Authentication Directive Kullanımı
Blade, kullanıcı giriş durumunu kontrol etmek için hazır directive’ler sunar.
@auth
<p>Hoş geldin, {{ auth()->user()->name }}</p>
<a href="{{ route('dashboard') }}">Panel</a>
@endauth
@guest
<a href="{{ route('login') }}">Giriş Yap</a>
<a href="{{ route('register') }}">Kayıt Ol</a>
@endguest
Yetki kontrolü için `@can` kullanılabilir:
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}">Düzenle</a>
@endcan
Bu kullanım policy yapısıyla birlikte çok temiz çalışır.
13. Admin Menü Örneği
Blade’i gerçek bir senaryoda düşünelim. Kullanıcı admin ise yönetim linki gösterelim:
<nav>
<a href="/">Ana Sayfa</a>
<a href="/blog">Blog</a>
@auth
@if (auth()->user()->is_admin)
<a href="{{ route('admin.dashboard') }}">Admin Panel</a>
@endif
@endauth
</nav>
Burada mantık basit ama sık kullanılır: auth kontrolü, sonra rol kontrolü.
14. Stack Kullanımı: @push ve @stack
Bazen sadece belirli sayfada ekstra CSS veya JS eklemek gerekir. Layout içinde `@stack` alanı açılır:
<head>
@vite(['resources/css/app.css', 'resources/js/app.js'])
@stack('styles')
</head>
<body>
@yield('content')
@stack('scripts')
</body>
Sayfa içinde:
@push('styles')
<link rel="stylesheet" href="/vendor/editor/editor.css">
@endpush
@push('scripts')
<script src="/vendor/editor/editor.js"></script>
@endpush
Bu sayede her sayfaya gereksiz script yüklemezsin.
15. JSON Veriyi JavaScript’e Aktarma
Backend’den gelen veriyi JS tarafına aktarmak gerektiğinde rastgele string birleştirmek yerine Laravel helper kullanmak daha güvenlidir.
<script>
window.chartData = @json($chartData);
</script>
Laravel’de `Js::from()` kullanımı da tercih edilebilir:
<script>
window.chartData = {{ Illuminate\Support\Js::from($chartData) }};
</script>
Bu yöntemler tırnak, özel karakter ve JSON escape problemlerini azaltır.
16. Raw PHP Kullanımı
Blade içinde çoğu zaman PHP yazmak gerekmez. Ama gerekiyorsa `@php` kullanılabilir:
@php
$readingTime = ceil(str_word_count(strip_tags($post->content)) / 200);
@endphp
<p>{{ $readingTime }} dk okuma</p>
Yine de ağır hesapları view içinde yapmak doğru değildir. Bu tarz değerleri model accessor, presenter, view model veya controller tarafında hazırlamak daha sağlıklı olur.
17. Özel Blade Directive Yazma
Çok tekrar eden küçük formatlama işleri için custom directive yazılabilir. `app/Providers/AppServiceProvider.php` içinde:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
Blade::directive('datetime', function ($expression) {
return "<?php echo ($expression)->format('d.m.Y H:i'); ?>";
});
}
}
Kullanım:
@datetime($post->published_at)
Custom directive faydalıdır ama abartılmamalıdır. Çok iş kuralı içeren şeyleri directive içine gömmek view tarafını karıştırır.
18. Blog Kart Component Örneği
Şimdi daha gerçekçi bir blog kartı yapalım.
`resources/views/components/post-card.blade.php`:
@props([
'post',
])
<article {{ $attributes->merge(['class' => 'post-card']) }}>
@if ($post->cover_image)
<img src="{{ asset('storage/'.$post->cover_image) }}" alt="{{ $post->title }}">
@endif
<div>
<time datetime="{{ $post->published_at?->toDateString() }}">
{{ $post->published_at?->format('d.m.Y') }}
</time>
<h2>
<a href="{{ route('posts.show', $post) }}">
{{ $post->title }}
</a>
</h2>
<p>{{ $post->excerpt }}</p>
</div>
</article>
Blog listesinde kullanım:
@foreach ($posts as $post)
<x-post-card :post="$post" class="mb-6" />
@endforeach
`:post="$post"` kullanımındaki iki nokta, attribute değerinin PHP değişkeni olduğunu söyler.
19. Sayfalama Linkleri
Controller tarafında:
$posts = Post::query()
->where('is_published', true)
->latest('published_at')
->paginate(12);
return view('blog.index', compact('posts'));
Blade tarafında:
@foreach ($posts as $post)
<x-post-card :post="$post" />
@endforeach
{{ $posts->links() }}
Laravel pagination linklerini otomatik üretir. Tailwind kullanan projelerde görünüm genelde hazır iyi gelir.
20. Validation Hatalarını Component Yapmak
Her input altında aynı `@error` yazmak yerine küçük component yapılabilir.
`resources/views/components/input-error.blade.php`:
@props(['name'])
@error($name)
<p {{ $attributes->merge(['class' => 'text-sm text-red-600']) }}>
{{ $message }}
</p>
@enderror
Kullanım:
<input name="title" value="{{ old('title') }}">
<x-input-error name="title" />
Bu küçük component bile form kodunu ciddi temizler.
21. Blade’de Sık Yapılan Hatalar
- View içinde çok iş kuralı yazmak: Vergi hesaplama, ödeme mantığı, karmaşık filtreleme view içinde olmamalı.
- {!! !!} kullanımını abartmak: Güvenilmeyen veri ham HTML basılırsa XSS açığı çıkar.
- Her yerde auth() çağırmak: Basit kullanımda sorun değil, ama karmaşık menülerde policy veya view composer daha temiz olabilir.
- Component’i her şeye çevirmek: Tek kullanılan basit HTML için component şart değildir.
- N+1 sorgu üretmek: Blade içinde `$post->comments->count()` gibi ilişkiler lazy load ederse performans sorunu olabilir. Controller’da `withCount()` kullan.
- Frontend scriptlerini her sayfaya koymak: `@push` ve `@stack` ile sadece gereken sayfada yükle.
22. Performans İçin Küçük Notlar
Blade hızlıdır ama yanlış veri hazırlama performansı bozar. Blog listesinde kategori ve yorum sayısı gösterilecekse controller tarafında eager loading kullan:
$posts = Post::query()
->with('category')
->withCount('comments')
->latest()
->paginate(12);
Blade içinde:
@foreach ($posts as $post)
<h2>{{ $post->title }}</h2>
<span>{{ $post->category->name }}</span>
<span>{{ $post->comments_count }} yorum</span>
@endforeach
Böylece her kartta ayrı ayrı sorgu çalışmaz.
23. Temiz Blade Yazmak İçin Pratik Kurallar
- Sayfanın ana iskeleti layout dosyasında olsun.
- Tekrar eden küçük parçaları partial veya component yap.
- Formlarda `@csrf`, `old()` ve `@error` kullanmayı unutma.
- Kullanıcı verisini varsayılan olarak `{{ }}` ile bas.
- Sayfaya özel JS/CSS için `@push` kullan.
- Karmaşık hesapları controller, service, model accessor veya view model tarafına taşı.
- Liste sayfalarında ilişkileri controller’da eager load et.
Kısa Komut ve Dosya Özeti
php artisan make:component Alert
php artisan make:component PostCard
resources/views/layouts/app.blade.php
resources/views/components/alert.blade.php
resources/views/components/post-card.blade.php
resources/views/blog/index.blade.php
resources/views/partials/navigation.blade.php
Sonuç
Laravel Blade, projeyi hızlı geliştirmek için çok güçlü ve sade bir view katmanıdır. İlk başta `@if`, `@foreach`, `@extends`, `@section` öğrenmek yeterli gibi görünür. Ama gerçek projede component, slot, form validation, auth directive, stack ve güvenli çıktı kullanımı işin kalitesini belirler.
Benim önerim şu: Blade’i sadece HTML içine PHP yazmanın kısa yolu gibi görme. Layout ile sayfa iskeletini kur, component ile tekrar eden parçaları toparla, slot ile esneklik sağla, form directive’leri ile güvenliği unutma. Böyle yazılan Blade dosyaları hem geliştirici için okunur olur hem proje büyüdükçe daha az dağılır.
Kaynak notu: Bu yazı Laravel 12 resmi Blade dokümantasyonu, Laravel view/component yaklaşımı ve gerçek proje pratikleri temel alınarak hazırlanmıştır.