Laravel İle Dinamik Bir Abonelik Ve Üyelik Planı Sistemi Nasıl Yapılır?

Laravel İle Dinamik Bir Abonelik Ve Üyelik Planı Sistemi Nasıl Yapılır?
Laravel İle Dinamik Bir Abonelik Ve Üyelik Planı Sistemi Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Bu projeyi hayata geçirmek için sisteminizde PHP 8.4 veya üzeri bir sürümün ve Laravel 12.x framework'ünün kurulu olması gerekmektedir. Veritabanı yönetimi için MySQL veya PostgreSQL kullanılması önerilir. Ayrıca, abonelik süreçlerini yönetmek için Laravel'in resmi paketi olan Laravel Cashier (Stripe tabanlı) kullanacağız.

  • PHP 8.4+
  • Laravel 12.x
  • Composer (Paket yöneticisi)
  • Stripe hesabı (Ödeme işlemleri için)

Kuruluma başlamadan önce terminalinizde projenizi oluşturduğunuzdan ve veritabanı bağlantı ayarlarınızı .env dosyasında yapılandırdığınızdan emin olun.

Veritabanı Şeması ve Planların Tanımlanması

Dinamik bir abonelik sistemi için ilk adım, planları ve kullanıcı aboneliklerini tutacak veritabanı tablolarını oluşturmaktır. Laravel Migration (veritabanı göçü) kullanarak plans tablosunu oluşturalım.


// Migration: Create plans table
Schema::create('plans', function (Blueprint $table) {
    $table->id();
    $table->string('name'); // Örn: Gold, Silver
    $table->string('slug')->unique(); // URL dostu isim
    $table->string('stripe_plan_id'); // Stripe üzerindeki plan ID
    $table->decimal('price', 8, 2);
    $table->integer('billing_interval_days');
    $table->timestamps();
});

Bu tablo, abonelik paketlerinizin temelini oluşturur. stripe_plan_id alanı, ödeme sağlayıcınızla senkronizasyonu sağlar. Bu sayede veritabanı üzerinden planları dinamik olarak güncelleyebilir veya yeni planlar ekleyebilirsiniz.

Kullanıcı Modeline Abonelik Yeteneklerinin Eklenmesi

Laravel Cashier, User modelinize Billable trait'ini ekleyerek abonelik yönetimi için gerekli tüm metodları sağlar. Bu, kullanıcıların aktif aboneliklerini kontrol etmeyi ve ödeme geçmişlerini sorgulamayı kolaylaştırır.


namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Cashier\Billable;

class User extends Authenticatable
{
    use Billable;

    // Kullanıcının aktif bir aboneliği olup olmadığını kontrol eder
    public function isSubscribedTo($planName)
    {
        return $this->subscribed($planName);
    }
}

Bu yapı, uygulamanızın farklı noktalarında $user->isSubscribedTo('gold') şeklinde basit kontroller yapmanıza olanak tanır. Bu yöntem, kodunuzun okunabilirliğini artırır ve karmaşık sorgulardan sizi kurtarır.

Abonelik Planları İçin Kontrolcü (Controller) Oluşturma

Kullanıcıların abonelik satın alma sürecini yönetmek için bir SubscriptionController oluşturmalıyız. Bu kontrolcü, ödeme formundan gelen veriyi işler ve Stripe üzerinden abonelik işlemini başlatır.


public function subscribe(Request $request, Plan $plan)
{
    $request->user()->newSubscription('default', $plan->stripe_plan_id)
        ->checkout([
            'success_url' => route('dashboard'),
            'cancel_url' => route('plans.index'),
        ]);
}

checkout metodu, kullanıcıyı güvenli bir şekilde Stripe ödeme sayfasına yönlendirir. Ödeme başarılı olduğunda, Stripe uygulamanıza bir Webhook gönderir ve Laravel bu Webhook'u dinleyerek veritabanındaki abonelik durumunu günceller.

Abonelik Yönetimi Yöntemlerinin Karşılaştırılması

Yöntem Avantajı Dezavantajı
Laravel Cashier Hızlı entegrasyon, güvenli ödeme Stripe bağımlılığı
Manuel Entegrasyon Tam kontrol, düşük komisyon Yüksek güvenlik riski, karmaşık bakım

Güvenlik ve Yetkilendirme (Middleware)

Abonelik gerektiren sayfalara erişimi kısıtlamak için özel bir Middleware (ara katman) oluşturmalısınız. Bu, ödemesi olmayan kullanıcıların premium içeriklere erişmesini engeller.


public function handle(Request $request, Closure $next)
{
    if ($request->user() && $request->user()->subscribed('default')) {
        return $next($request);
    }

    return redirect()->route('plans.index')->with('error', 'Bu içeriğe erişmek için abonelik gereklidir.');
}

Güvenlik Uyarısı: Ödeme verilerini asla kendi veritabanınızda saklamayın. PCI-DSS uyumluluğu için her zaman Stripe veya benzeri bir ödeme sağlayıcısının sağladığı güvenli token sistemlerini kullanın. XSS saldırılarına karşı tüm kullanıcı girdilerini Blade şablonlarında {{ $variable }} sözdizimi ile escape ederek yazdırın.

Sıkça Sorulan Sorular

Abonelik iptal süreçlerini nasıl yönetmeliyim?

Laravel Cashier ile $user->subscription('default')->cancel() metodunu kullanarak aboneliği kolayca iptal edebilirsiniz. Bu işlem, bir sonraki fatura dönemine kadar aboneliğin aktif kalmasını sağlar.

Farklı para birimleri ile çalışabilir miyim?

Evet, Stripe ayarlarınız üzerinden ve .env dosyanızdaki yapılandırmalarla farklı para birimlerini destekleyebilirsiniz. Ancak, veritabanınızda fiyatları saklarken kur değişimlerini göz önünde bulundurmalısınız.

Kullanıcı aboneliği bittiğinde verileri ne yapmalıyım?

Abonelik süresi dolduğunda verileri silmek yerine, kullanıcıyı bir "Free" plana düşürmek veya erişimini sınırlamak en iyi pratik olarak kabul edilir.

Webhook'lar neden gereklidir?

Webhook'lar, ödeme sağlayıcınızdan gelen asenkron bildirimleri dinler. Örneğin, kredi kartı reddedildiğinde sisteminizin otomatik olarak aboneliği durdurması için Webhook kullanımı zorunludur.

Test ortamında nasıl ödeme yapabilirim?

Stripe'ın sunduğu test kart numaralarını kullanarak, gerçek para çekilmeden tüm ödeme akışınızı test edebilirsiniz.

Abonelik Sistemlerinde Performans Optimizasyonu ve Önbellekleme

Dinamik abonelik sistemlerinde, her sayfa yüklemesinde veritabanına giderek kullanıcının abonelik durumunu kontrol etmek, özellikle yüksek trafikli uygulamalarda ciddi bir performans darboğazı yaratabilir. Laravel'in sunduğu önbellekleme mekanizmalarını kullanarak bu sorgu yükünü minimize edebilirsiniz.

Kullanıcının abonelik durumunu User modeli içerisinde bir metot olarak tanımlayıp, bu veriyi Redis veya Memcached üzerinde tutmak en verimli yöntemdir. Aşağıdaki örnekte, abonelik durumunun nasıl önbelleğe alınacağı gösterilmiştir:

public function isSubscribed()
{
    return Cache::remember('user_sub_status_' . $this->id, 3600, function () {
        return $this->subscriptions()->active()->exists();
    });
}

Bu yapıyı kullandığınızda, abonelik durumu değiştiğinde (örneğin ödeme alındığında veya iptal edildiğinde) ilgili önbellek anahtarını temizlemeyi unutmamalısınız:

public function updateSubscriptionStatus($userId)
{
    // Abonelik güncelleme işlemleri...
    Cache::forget('user_sub_status_' . $userId);
}

Abonelik Süreçlerinde Hata Ayıklama (Debugging)

Ödeme sistemleri asenkron çalıştığı için (webhook'lar üzerinden), hataları takip etmek bazen zorlayıcı olabilir. Laravel'in Log sınıfını kullanarak, Stripe'tan gelen her isteği ve sistemin verdiği tepkiyi kayıt altına almanız, olası bir ödeme başarısızlığında sorunu hızlıca tespit etmenizi sağlar.

Webhook rotanızda gelen veriyi şu şekilde loglayabilirsiniz:

use Illuminate\Support\Facades\Log;

public function handleWebhook(Request $request)
{
    $payload = $request->all();
    
    Log::info('Stripe Webhook Alındı:', [
        'event' => $payload['type'] ?? 'unknown',
        'data' => $payload['data']['object']['id'] ?? 'N/A'
    ]);

    // İşleme devam et...
}

Ayrıca, Stripe Dashboard üzerinde bulunan "Events" sekmesini kullanarak, başarısız olan webhook isteklerini tekrar tetikleyebilir ve uygulamanızın verdiği hata kodlarını inceleyebilirsiniz. Geliştirme aşamasında stripe listen --forward-to localhost:8000/stripe/webhook komutunu kullanarak yerel ortamınıza gelen istekleri canlı olarak izlemek, hata ayıklama sürecini büyük ölçüde hızlandıracaktır.

Önemli İpuçları ve En İyi Uygulamalar

  • Grace Period (İzin Süresi): Kullanıcının ödemesi başarısız olduğunda aboneliği hemen kapatmak yerine, 3-5 günlük bir "grace period" tanımlayarak kullanıcıya ödeme bilgilerini güncellemesi için zaman tanıyın.
  • Veri Tutarlılığı: Veritabanınızdaki abonelik tablosu ile Stripe üzerindeki verilerin eşleştiğinden emin olmak için günlük "cron job"lar ile senkronizasyon kontrolleri yapın.
  • Güvenlik: Webhook uç noktalarınızın sadece Stripe'tan gelen istekleri kabul ettiğinden emin olmak için imza doğrulama (signature verification) yöntemini mutlaka aktif edin.

Sonuç

Laravel ile dinamik bir abonelik sistemi kurmak, Cashier gibi güçlü araçlar sayesinde oldukça verimli bir süreçtir. Bu rehberde, veritabanı tasarımından başlayarak, kullanıcı yetkilendirme ve ödeme entegrasyonuna kadar kritik adımları inceledik. Bir sonraki adım olarak, Stripe Webhook'larını detaylıca yapılandırarak abonelik yenileme ve iptal süreçlerini tam otomatize etmeyi deneyebilirsiniz.

Sorumluluk Reddi: Bu makalede paylaşılan kodlar eğitim amaçlıdır. Canlıya almadan önce ödeme sisteminizin güvenliğini ve veri gizliliği politikalarınızı bir güvenlik uzmanına onaylatmanız önemle tavsiye edilir.

Bu yazıya tepkinizi paylaşın:
Zeynep Arslan

Mutfak pratikleri ve ev düzeni konularında yıllardır içerik üretiyorum. Okuyuculara zaman kazandıran, uygulanabilir ve sürdürülebilir yaşam tarzı önerileri sunuyorum.

Yorumlar (16)

16
okuyucu bu yazı hakkında yorum yaptı. Siz de deneyiminizi paylaşarak diğer okuyuculara yardımcı olabilirsiniz.
Zehra Nur
Zehra Nur 30 Temmuz 2026

Çok temiz anlatmışsın, ellerine sağlık. Özellikle middleware kısımları çok işime yaradı.

Hakan Vural
Hakan Vural 31 Temmuz 2026

Kod bloklarındaki renklendirme biraz daha belirgin olabilirmiş mobilden girince zor okunuyor ama içerik 10 numara.

Zeynep Arslan
Zeynep Arslan 01 Ağustos 2026

Geri bildirimin için teşekkürler Hakan, tasarım tarafındaki bu sorunu en kısa sürede düzelteceğim.

Deniz Kara
Deniz Kara 01 Ağustos 2026

Gayet açıklayıcı ve temiz bir kod yapısı olmuş. Türkiye'deki ödeme sistemleri (Iyzico vs.) için de benzer bir rehber gelebilir mi ileride?

Zeynep Arslan
Zeynep Arslan 02 Ağustos 2026

Iyzico çokça soruluyor, notlarımı aldım, en kısa sürede eklemeye çalışacağım.

Fatma Şen
Fatma Şen 02 Ağustos 2026

Yazı için teşekürler, veritabanı şeması kısmında kafam biraz karıştı ama kodları incelince oturdu taşlar yerine.

Caner Yılmaz
Caner Yılmaz 03 Ağustos 2026

Laravel 12 ile Stripe entegrasyonu beklediğim bir konuydu, eline sağlık Zeynep. Cashier tarafında webhook yapılandırmasını biraz daha detaylandırsan harika olurdu aslında.

Zeynep Arslan
Zeynep Arslan 04 Ağustos 2026

Güzel önerin için teşekkürler Caner, webhook'lar üzerine ayrı bir rehber hazırlamayı planlıyorum, takipte kal!

Tolga Y.
Tolga Y. 03 Ağustos 2026

Abonelik iptal süreçlerini nasıl yönettin? Orada kullanıcı deneyimi açısından bişeyler ekledin mi yoksa sadece backend mi?

Selin Baş
Selin Baş 04 Ağustos 2026

Harika anlatım, tam aradığım şeydi. Stripe'ın test modunda kart bilgilerini girerken hata alıyordum ama senin adımları takip edince çözdüm. Çok saol.

Mertcan
Mertcan 05 Ağustos 2026

Aynı sorunu yaşamıştım, Stripe'ın o test kart numaraları bazen yanıltıcı olabiliyor, iyi ki halletmişsin.

Emre Aydın
Emre Aydın 05 Ağustos 2026

Stripe yerine farklı bir ödeme yöntemi kullanmak istersek Cashier'ın esnekliği ne durumda? Bilgin var mı?

Gökhan
Gökhan 06 Ağustos 2026

Cashier genelde Stripe odaklı, başka yapı için kendi driver'ını yazman gerekebilir ya da farklı kütüphanelere bakmanı öneririm.

Burak Özdemir
Burak Özdemir 05 Ağustos 2026

Ya bu Laravel sürümleri çok hızlı güncelleniyo, 12'ye geçişte büyük değişiklikler var mı? Projeyi taşımaya değer mi?

Zeynep Arslan
Zeynep Arslan 06 Ağustos 2026

Performans ve tip güvenliği tarafında ciddi iyileştirmeler var Burak, yeni bir proje için kesinlikle değer.

Ceren Ak
Ceren Ak 06 Ağustos 2026

Baya faydalı oldu, ödevim için referans alıyorum. Başarıların devamını dilerim.

Yorum Yaz