Gereksinimler ve Ön Hazırlık
Projeye başlamadan önce sisteminizde PHP 8.2+ ve Laravel 11 yüklü olmalıdır. Ayrıca veritabanı yönetimi için MySQL veya PostgreSQL kullanıyor olmanız beklenmektedir. Proje dizininizde terminali açarak gerekli paketlerin ve ortamın hazır olduğundan emin olun.
- PHP 8.2 veya daha yeni bir sürüm.
- Composer paket yöneticisi.
- Laravel 11 framework kurulumu.
- Veritabanı bağlantı ayarlarının .env dosyasında yapılandırılmış olması.
Veritabanı Şeması ve Migration Oluşturma
Dinamik tercihler için en verimli yöntem, "JSON" sütun tipini veya ayrı bir "preferences" tablosunu kullanmaktır. Biz, esnekliği artırmak adına ayrı bir tablo yapısını tercih edeceğiz. Bu sayede kullanıcılar silindiğinde tercihleri de otomatik olarak temizlenebilir.
Aşağıdaki komutla migration dosyasını oluşturun:
php artisan make:migration create_user_preferences_table
Oluşturulan migration dosyasını şu şekilde güncelleyin:
public function up(): void
{
Schema::create('user_preferences', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('key'); // Örn: 'theme', 'language'
$table->text('value'); // Örn: 'dark', 'tr'
$table->timestamps();
$table->unique(['user_id', 'key']); // Aynı anahtarın tekrarını engeller
});
}
Bu yapı, her kullanıcının sınırsız sayıda tercih eklemesine olanak tanır. unique kısıtlaması, veri bütünlüğünü korumak için kritiktir.
Eloquent İlişkilerini Tanımlama
Tercihleri kullanıcı nesnesi üzerinden kolayca yönetebilmek için User modeline bir ilişki eklememiz gerekir. Bu, kodun okunabilirliğini ve yönetilebilirliğini artırır.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class User extends Model
{
public function preferences(): HasMany
{
return $this->hasMany(UserPreference::class);
}
}
Bu ilişki sayesinde $user->preferences diyerek kullanıcının tüm ayarlarını bir koleksiyon olarak çekebilirsiniz.
Tercihleri Yönetmek İçin Servis Sınıfı Oluşturma
İş mantığını controller içerisinde tutmak yerine bir servis sınıfı (Service Class) kullanmak, temiz kod prensipleri (Clean Code) açısından önemlidir. PreferenceService sınıfı, tercihleri okuma ve yazma işlemlerini merkezi hale getirir.
namespace App\Services;
use App\Models\User;
class PreferenceService
{
public function set(User $user, string $key, string $value): void
{
$user->preferences()->updateOrCreate(
['key' => $key],
['value' => $value]
);
}
public function get(User $user, string $key, $default = null)
{
return $user->preferences()->where('key', $key)->value('value') ?? $default;
}
}
updateOrCreate metodu, eğer anahtar zaten mevcutsa günceller, değilse yeni bir kayıt oluşturur. Bu, veritabanı işlemlerinde hata payını sıfıra indirir.
Dinamik Tercihlerin Controller ile Kullanımı
Kullanıcının tercihlerini güncellemek için bir Controller oluşturun. Burada dikkat etmemiz gereken en önemli nokta, kullanıcı girdilerinin doğrulanmasıdır (Validation).
public function update(Request $request, PreferenceService $service)
{
$validated = $request->validate([
'key' => 'required|string|max:50',
'value' => 'required|string|max:255',
]);
$service->set(auth()->user(), $validated['key'], $validated['value']);
return response()->json(['message' => 'Tercih başarıyla güncellendi.']);
}
Bu yöntemle, kullanıcı arayüzünden gelen veriler güvenli bir şekilde işlenir ve veritabanına kaydedilir.
Performans ve Güvenlik Karşılaştırması
Tercih yönetimi sistemleri için kullanılan farklı yaklaşımların karşılaştırması aşağıdadır:
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| JSON Sütunu (User tablosunda) | Hızlı sorgulama | Veri boyutu arttıkça yavaşlar |
| Ayrı Tablo (Önerilen) | Ölçeklenebilir | İlişkili sorgu gerektirir |
| Redis (Önbellek) | Çok hızlı | Kalıcı değil (veri kaybı riski) |
Kritik Güvenlik Uyarısı: Kullanıcı tercihlerini işlerken her zaman "Mass Assignment" (Toplu Atama) açığına karşı
$fillableözelliklerini modelinizde doğru tanımlayın. Ayrıca, kullanıcıdan gelen verileri asla doğrudan HTML çıktısına yazdırmayın; Blade motorunun{{ $value }}sözdizimini kullanarak otomatik XSS korumasından faydalanın.
Sıkça Sorulan Sorular
Tercihleri her sayfada veritabanından çekmek performansı düşürür mü?
Evet, her sayfada veritabanına gitmek performans kaybına yol açar. Bu yüzden, oturum açan kullanıcının tercihlerini giriş yaptıktan sonra "Cache" veya "Session" üzerinde tutmanız önerilir.
Aynı anahtar için birden fazla değer tutabilir miyim?
Eğer böyle bir ihtiyacınız varsa, value sütununu json tipine çevirerek Laravel'in JSON cast özelliklerini kullanabilirsiniz.
Kullanıcı silindiğinde tercihler ne olur?
Migration dosyasında kullandığımız onDelete('cascade') özelliği sayesinde, kullanıcı veritabanından silindiğinde tüm tercihleri otomatik olarak temizlenir.
Tercihleri varsayılan değerlerle nasıl desteklerim?
Servis sınıfındaki get metodunda belirttiğimiz $default parametresi, eğer veritabanında kayıt yoksa uygulamanın varsayılan değeri döndürmesini sağlar.
Bu sistem çok dilli uygulamalarda çalışır mı?
Evet, key parametresini 'locale' olarak ayarlayıp value kısmında 'tr', 'en' gibi değerler tutarak dinamik dil yönetimi yapabilirsiniz.
İleri Seviye İpuçları: Tercihleri Önbellekleme (Caching) ile Optimize Etme
Veritabanı sorgularını azaltmak ve uygulamanızın yanıt süresini milisaniyelere indirmek için Laravel'in güçlü önbellekleme mekanizmasını kullanmak kritik öneme sahiptir. Kullanıcı her sayfa yenilediğinde veritabanına gitmek yerine, tercihleri Redis veya Memcached üzerinde tutarak sistem performansını maksimize edebilirsiniz.
Aşağıdaki örnekte, PreferenceService sınıfımıza tercihler güncellendiğinde önbelleği otomatik temizleyen ve okuma yaparken önbelleği kontrol eden bir yapı ekliyoruz:
use Illuminate\Support\Facades\Cache;
public function getPreference(int $userId, string $key, $default = null)
{
$cacheKey = "user_{$userId}_prefs";
return Cache::remember($cacheKey, now()->addHours(24), function () use ($userId) {
return UserPreference::where('user_id', $userId)->pluck('value', 'key')->toArray();
})[$key] ?? $default;
}
public function updatePreference(int $userId, string $key, string $value)
{
UserPreference::updateOrCreate(
['user_id' => $userId, 'key' => $key],
['value' => $value]
);
// Güncelleme sonrası önbelleği temizle
Cache::forget("user_{$userId}_prefs");
}
Test Süreçleri: Tercih Yönetimini Güvence Altına Almak
Dinamik bir sistemde, kullanıcı tercihlerinin doğru kaydedilip kaydedilmediğini doğrulamak için birim testleri (unit tests) yazmak projenizin sürdürülebilirliği için zorunludur. Laravel'in Pest veya PHPUnit kütüphanelerini kullanarak tercihlerin veritabanı ile uyumunu şu şekilde test edebilirsiniz:
public function test_user_can_update_theme_preference()
{
$user = User::factory()->create();
$service = new PreferenceService();
$service->updatePreference($user->id, 'theme', 'dark');
$this->assertDatabaseHas('user_preferences', [
'user_id' => $user->id,
'key' => 'theme',
'value' => 'dark'
]);
}
Hata Ayıklama (Debugging) Stratejileri
Sisteminiz büyüdükçe, hangi kullanıcının hangi tercihi ne zaman değiştirdiğini takip etmek zorlaşabilir. Bu noktada Laravel'in Log mekanizmasını veya Audit paketlerini kullanmanız önerilir. Özellikle kritik tercihlerde (örneğin: bildirim ayarları veya hesap gizliliği) yapılan değişiklikleri şu şekilde loglayabilirsiniz:
- Log Seviyesi: Değişiklikleri
infoseviyesinde kaydedin. - Context: Log kaydına mutlaka
user_idveip_addressbilgilerini ekleyin. - İzleme: Laravel Telescope kullanarak veritabanı sorgularını anlık izleyin.
use Illuminate\Support\Facades\Log;
public function updatePreference(int $userId, string $key, string $value)
{
// ... güncelleme işlemleri ...
Log::info("Kullanıcı tercihi güncellendi", [
'user_id' => $userId,
'key' => $key,
'new_value' => $value,
'timestamp' => now()
]);
}
Sonuç
Laravel ile dinamik bir kullanıcı tercihleri yönetim sistemi oluşturmak, uygulamanızın kullanıcı merkezli bir yapıya evrilmesini sağlar. Bu rehberde öğrendiğiniz veritabanı şeması, servis katmanı ve Eloquent ilişkileri, projenizin temelini sağlamlaştıracaktır. Bir sonraki adım olarak, bu tercihleri bir "Middleware" kullanarak uygulama genelinde otomatik olarak yükleyen bir yapı kurmayı deneyebilirsiniz.
Yasal Uyarı: Bu rehberdeki kod örnekleri eğitim amaçlıdır. Üretim (production) ortamında veritabanı işlemlerinde her zaman işlemlerinizi (transactions) kullanmayı ve hassas verileri şifrelemeyi unutmayın. Yazılım güvenliği sorumluluğu geliştiriciye aittir.

Yorumlar (0)
Yorum Yaz