Fikir: Tüm Dağıtımlar Tek Tabloda
Mevcut Durum (3 Ayrı Tablo)
playlist_sector
playlist_radio
playlist_corporate (yeni)
3 tablo, 3 migration, 3 relation method...
v5 Önerisi (1 Unified Tablo)
playlistables
playlist_id → Playlist
playlistable_id → Target ID
playlistable_type → 'sector' | 'radio' | 'corporate'
1 tablo, 1 migration, polymorphic relation!
Dönüşüm
ÖNCE (3 Ayrı Pivot Tablo): ┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐ │ playlist_sector │ │ playlist_radio │ │ playlist_corporate │ ├──────────────────────┤ ├──────────────────────┤ ├──────────────────────┤ │ playlist_id │ │ playlist_id │ │ playlist_id │ │ sector_id │ │ radio_id │ │ corporate_id │ └──────────────────────┘ └──────────────────────┘ └──────────────────────┘ │ │ │ └─────────────────────────┼─────────────────────────┘ │ ▼ SONRA (1 Unified Tablo): ┌────────────────────────────────┐ │ playlistables │ ├────────────────────────────────┤ │ id (PK) │ │ playlist_id (FK) │ │ playlistable_id │ │ playlistable_type │ ← 'sector', 'radio', 'corporate' │ created_at (optional) │ └────────────────────────────────┘ │ ┌───────────────────────┼───────────────────────┐ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Sector │ │ Radio │ │ Corporate │ └─────────────┘ └─────────────┘ └─────────────┘
Migration
create_playlistables_table.php
Schema::create('playlistables', function (Blueprint $table) {
$table->id();
$table->foreignId('playlist_id')
->constrained('muzibu_playlists', 'playlist_id')
->cascadeOnDelete();
// Polymorphic columns
$table->unsignedBigInteger('playlistable_id');
$table->string('playlistable_type', 50);
$table->timestamps();
// Unique constraint: Aynı playlist + aynı target + aynı type = 1 kayıt
$table->unique(['playlist_id', 'playlistable_id', 'playlistable_type'], 'playlistables_unique');
// Indexes for fast queries
$table->index(['playlistable_type', 'playlistable_id'], 'playlistables_morph_idx');
$table->index('playlist_id');
});
Data Migration (Mevcut Verileri Taşı)
// Mevcut sector verilerini taşı
DB::table('muzibu_playlist_sector')->get()->each(function($row) {
DB::table('playlistables')->insert([
'playlist_id' => $row->playlist_id,
'playlistable_id' => $row->sector_id,
'playlistable_type' => 'sector',
]);
});
// Mevcut radio verilerini taşı
DB::table('muzibu_playlist_radio')->get()->each(function($row) {
DB::table('playlistables')->insert([
'playlist_id' => $row->playlist_id,
'playlistable_id' => $row->radio_id,
'playlistable_type' => 'radio',
]);
});
Model Implementation
Playlist.php
/**
* Sektörler (polymorphic)
*/
public function sectors()
{
return $this->morphedByMany(
Sector::class,
'playlistable',
'playlistables',
'playlist_id',
'playlistable_id',
'playlist_id',
'sector_id'
);
}
/**
* Radyolar (polymorphic)
*/
public function radios()
{
return $this->morphedByMany(
Radio::class,
'playlistable',
'playlistables',
'playlist_id',
'playlistable_id',
'playlist_id',
'radio_id'
);
}
/**
* Kurumlar (polymorphic) - YENİ!
*/
public function corporates()
{
return $this->morphedByMany(
MuzibuCorporateAccount::class,
'playlistable',
'playlistables',
'playlist_id',
'playlistable_id',
'playlist_id',
'id'
);
}
Target Models (Sector, Radio, Corporate)
// Sector.php
public function playlists()
{
return $this->morphToMany(
Playlist::class,
'playlistable',
'playlistables',
'playlistable_id',
'playlist_id',
'sector_id',
'playlist_id'
);
}
// Radio.php - Aynı pattern
public function playlists() { /* ... */ }
// MuzibuCorporateAccount.php - Aynı pattern
public function playlists()
{
return $this->morphToMany(
Playlist::class,
'playlistable',
'playlistables',
'playlistable_id',
'playlist_id',
'id',
'playlist_id'
);
}
Morph Map (AppServiceProvider)
// app/Providers/AppServiceProvider.php → boot()
Relation::morphMap([
'sector' => Sector::class,
'radio' => Radio::class,
'corporate' => MuzibuCorporateAccount::class,
]);
// Bu sayede DB'de 'sector' yazıyor, tam class adı değil
// Daha temiz, daha kısa, daha okunabilir
Kullanım (v4 ile Aynı!)
En güzel yanı: Kullanım syntax'ı değişmiyor!
Playlist'e Kurum Ekle
$playlist->corporates()->attach($id);
Kurumun Playlistleri
$corporate->playlists()->get();
Playlist'in Sektörleri
$playlist->sectors()->get();
Sync Multiple
$playlist->corporates()->sync([1, 5, 12]);
v4 vs v5 Karşılaştırma
v4: Ayrı Tablo (Mevcut Pattern)
Mevcut kodu değiştirmeye gerek yok
Data migration yok
Risk düşük
3 ayrı tablo = daha fazla bakım
Gelecekte yeni tip eklenirse +1 tablo
En uygun: Hızlı çözüm, minimum risk
v5: Unified Table (Polymorphic)
Tek tablo = tek bakım noktası
Gelecekte yeni tip = sadece morph map
Daha elegant, Laravel best practice
Mevcut relation'ları değiştirmek gerekir
Data migration gerekli
En uygun: Uzun vadeli, temiz mimari
Alternatif: Hibrit Yaklaşım
Mevcut tabloları koru, yeni için unified
Eğer mevcut sector/radio tablolarını değiştirmek istemiyorsan:
playlist_sector→ Olduğu gibi kalsınplaylist_radio→ Olduğu gibi kalsınplaylist_corporate→ v4 pattern ile ekle- Gelecekte gerekirse → Unified'a migrate et
Bu "pragmatik" yaklaşım: Şimdi çalışan şeyi bozmadan ilerle, gerekirse refactor
Karar Matrisi
| Öncelik | v4 Seç | v5 Seç |
|---|---|---|
| Hızlı teslim | ||
| Minimum risk | ||
| Uzun vadeli bakım | ||
| Gelecekte yeni tipler | ||
| Elegant mimari | ||
| Test edilmiş pattern |
🤔
Sen Karar Ver
🚀
v4: Şimdi Çalışsın
Mevcut pattern, yeni pivot tablo
Hızlı, güvenli, test edilmiş
🏗️
v5: Geleceğe Yatırım
Unified tablo, polymorphic
Temiz mimari, ölçeklenebilir
Tavsiyem: v4 ile başla, çalışsın. İleride gerekirse v5'e migrate et.