Gereksinimler ve Ön Hazırlık
Bu projeyi hayata geçirmek için bilgisayarınızda bir yerel geliştirme ortamı (XAMPP, WAMP veya Docker tabanlı bir yapı) kurulu olmalıdır. PHP 8.2 veya daha güncel bir sürüm kullanmanız, tip güvenliği (type hinting) ve performans iyileştirmelerinden yararlanmanızı sağlar.
- PHP 8.2+ sürümü yüklü bir sunucu ortamı.
- MySQL veya MariaDB veritabanı yönetim sistemi.
- PDO (PHP Data Objects) eklentisi (Veritabanı işlemleri için standarttır).
- Composer (Opsiyonel ancak PSR standartları için önerilir).
Veritabanı Tasarımı: Sık Kullanılanlar Tablosu
Dinamik bir sistem için veritabanı şemanızın normalize edilmiş olması gerekir. Kullanıcı kimliği (user_id) ve içerik kimliği (item_id) üzerinden bir ilişki kuracağız. Aşağıdaki SQL komutu ile gerekli tabloyu oluşturabilirsiniz.
CREATE TABLE user_favorites (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
item_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY unique_favorite (user_id, item_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Bu tabloda unique_favorite anahtarı, aynı kullanıcının bir içeriği birden fazla kez favorilere eklemesini engelleyerek veri bütünlüğünü korur.
Nesne Yönelimli Favori Yönetim Sınıfı
Favori işlemlerini yönetmek için bir FavoriteManager sınıfı oluşturacağız. Bu sınıf, veritabanı bağımlılığını enjekte ederek (Dependency Injection) test edilebilirliği artıracaktır.
class FavoriteManager {
private PDO $db;
public function __construct(PDO $db) {
$this->db = $db;
}
public function addFavorite(int $userId, int $itemId): bool {
$stmt = $this->db->prepare("INSERT IGNORE INTO user_favorites (user_id, item_id) VALUES (?, ?)");
return $stmt->execute([$userId, $itemId]);
}
public function removeFavorite(int $userId, int $itemId): bool {
$stmt = $this->db->prepare("DELETE FROM user_favorites WHERE user_id = ? AND item_id = ?");
return $stmt->execute([$userId, $itemId]);
}
}
Bu sınıf, veritabanı bağlantısını dışarıdan alır. INSERT IGNORE kullanımı, mükerrer kayıt hatası almadan işlemin güvenli bir şekilde sonuçlanmasını sağlar.
Dinamik Listeleme ve Veri Çekme
Kullanıcının favorilerini listelemek için getUserFavorites metodunu sınıfımıza ekleyelim. Bu metod, kullanıcının favori listesini bir dizi olarak döndürecektir.
public function getUserFavorites(int $userId): array {
$stmt = $this->db->prepare("SELECT item_id FROM user_favorites WHERE user_id = ? ORDER BY created_at DESC");
$stmt->execute([$userId]);
return $stmt->fetchAll(PDO::FETCH_COLUMN);
}
Bu metod, sadece item_id değerlerini döner. Eğer favori öğelerin detaylarını da (başlık, resim vb.) çekmek isterseniz, bu ID'leri kullanarak ana tablonuzla bir JOIN işlemi yapmanız gerekecektir.
Güvenlik ve Performans Karşılaştırması
Aşağıdaki tablo, favori sistemleri geliştirirken kullanılan farklı yaklaşımların avantaj ve dezavantajlarını özetlemektedir.
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Veritabanı (RDBMS) | Veri tutarlılığı, ilişkisel sorgu imkanı. | Yüksek trafikli sitelerde sorgu yükü. |
| Redis (Cache) | Çok hızlı okuma/yazma performansı. | Veri kalıcılığı yönetimi gerektirir. |
| Session/Cookie | Sunucu yükü yok, hızlı. | Cihaz değişince favoriler kaybolur. |
Güvenlik Uyarısı: Kullanıcıdan gelen
user_idveyaitem_idverilerini asla doğrudan sorguya dahil etmeyin. Her zaman PDO'nun hazırlanan ifadelerini (prepared statements) kullanarak SQL Injection saldırılarını engelleyin. Ayrıca, oturum yönetimini (session) her zaman güvenli (secure) ve HTTP-only bayraklarıyla yapılandırın.
Uygulama: Favori Ekleme İşlemini Tetikleme
Kullanıcı bir butona tıkladığında, bu isteği işleyecek bir PHP dosyası oluşturmalıyız. Bu dosya, sınıfımızı kullanarak veritabanı işlemini gerçekleştirecektir.
// favorite_action.php
require_once 'db_connection.php';
require_once 'FavoriteManager.php';
session_start();
$userId = $_SESSION['user_id'] ?? 0;
$itemId = (int)$_POST['item_id'];
if ($userId > 0) {
$manager = new FavoriteManager($pdo);
$manager->addFavorite($userId, $itemId);
echo json_encode(['status' => 'success']);
} else {
http_response_code(403);
echo json_encode(['status' => 'error', 'message' => 'Giriş yapmalısınız.']);
}
Bu kod bloğu, istemci tarafındaki JavaScript (Fetch API) ile haberleşmek için JSON formatında yanıt döner. Bu sayede sayfa yenilenmeden favori ekleme işlemi tamamlanır.
Sıkça Sorulan Sorular
Favori listesini önbelleğe (cache) almalı mıyım?
Eğer uygulamanız çok yüksek trafik alıyorsa, kullanıcının favori listesini Redis gibi bir bellek içi depolama sisteminde tutmak veritabanı yükünü ciddi oranda azaltacaktır.
SQL Injection'dan nasıl korunurum?
Yukarıdaki örneklerde olduğu gibi PDO prepared statements kullanarak veriyi sorgudan ayırın. Asla kullanıcıdan gelen veriyi doğrudan string birleştirme ile sorguya eklemeyin.
Aynı öğeyi birden fazla eklemeyi nasıl engellerim?
Veritabanı seviyesinde UNIQUE KEY tanımlayarak ve INSERT IGNORE komutunu kullanarak, veritabanı düzeyinde mükerrer kayıtların önüne geçebilirsiniz.
Favori listesini nasıl silerim?
FavoriteManager sınıfına eklediğimiz removeFavorite metodunu kullanarak, kullanıcının seçtiği item_id değerini veritabanından kolayca silebilirsiniz.
Çok fazla favori öğesi varsa ne yapmalıyım?
Veritabanı sorgularınıza LIMIT ve OFFSET ekleyerek sayfalama (pagination) yapısını kullanmanız, performansı korumak için en iyi yoldur.
İleri Seviye İpuçları: Favori Sistemini Ölçeklendirme
Sisteminiz büyüdükçe, veritabanı üzerindeki yükü azaltmak ve kullanıcı deneyimini iyileştirmek için bazı optimizasyon stratejileri uygulamanız gerekir. Nesne yönelimli yapınızı koruyarak, favori işlemlerini daha performanslı hale getirmek için şu yöntemleri değerlendirebilirsiniz:
Redis ile Hızlı Erişim Sağlama
Veritabanı sorguları (SELECT COUNT(*)) yüksek trafikli sitelerde darboğaz yaratabilir. Favori sayılarını Redis gibi bir anahtar-değer deposunda tutmak, veritabanı üzerindeki yükü neredeyse sıfıra indirir. Aşağıdaki örnek, favori sayısını Redis üzerinde nasıl güncelleyeceğinizi gösterir:
class RedisFavoriteManager {
private $redis;
public function __construct() {
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
public function incrementFavoriteCount($itemId) {
$key = "item_fav_count:" . $itemId;
return $this->redis->incr($key);
}
public function getFavoriteCount($itemId) {
return $this->redis->get("item_fav_count:" . $itemId) ?: 0;
}
}
Birim Testleri (Unit Testing) ile Kod Kalitesini Artırma
Geliştirdiğiniz FavoriteManager sınıfının her senaryoda doğru çalıştığından emin olmak için PHPUnit kullanmanız önerilir. Özellikle favori ekleme ve silme gibi kritik fonksiyonların, beklenmedik durumlarda (örneğin veritabanı bağlantı hatası) nasıl tepki verdiğini test etmelisiniz.
Örnek Test Senaryosu
Aşağıdaki kod bloğu, favori ekleme fonksiyonunun başarılı olup olmadığını kontrol eden temel bir test yapısını temsil eder:
use PHPUnit\Framework\TestCase;
class FavoriteManagerTest extends TestCase {
public function testAddFavoriteReturnsTrueOnSuccess() {
$db = $this->createMock(PDO::class);
$manager = new FavoriteManager($db);
// Mock veritabanı işlemleri burada tanımlanır
$result = $manager->addFavorite(1, 101);
$this->assertTrue($result);
}
}
Deployment Öncesi Kontrol Listesi
- İndeksleme: Veritabanında
user_idveitem_idsütunlarına mutlakaINDEXeklediğinizden emin olun. Bu, sorgu hızını 10 katına kadar artırabilir. - Hata Günlüğü: Veritabanı hatalarını kullanıcıya göstermek yerine,
error_log()fonksiyonu ile sunucu tarafındaki bir dosyaya kaydedin. - Input Sanitization: Kullanıcıdan gelen tüm ID değerlerini
(int)tip dönüşümü ile zorunlu kılın.
Bu ileri seviye yaklaşımlar, uygulamanızın sadece çalışmasını değil, aynı zamanda binlerce kullanıcıya aynı anda hizmet verebilecek kapasiteye ulaşmasını sağlar. Kodunuzu modüler tutarak, ileride veritabanı yapısını değiştirseniz bile iş mantığınızı (business logic) korumuş olursunuz.
Sonuç
PHP ile nesne yönelimli bir yapıda dinamik sık kullanılanlar listesi oluşturmak, doğru veritabanı tasarımı ve güvenli kodlama pratikleri ile oldukça verimli bir süreçtir. Bu rehberde öğrendiğiniz FavoriteManager sınıfı yapısı, projenizin ilerleyen aşamalarında yeni özellikler eklemenize olanak tanır. Bir sonraki adım olarak, favori listesini AJAX kullanarak dinamik bir arayüzle kullanıcıya göstermeyi ve favori sayısını gerçek zamanlı güncellemeyi hedefleyebilirsiniz.
Yasal Sorumluluk Reddi: Bu makaledeki kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce mutlaka hata ayıklama (debug) süreçlerini tamamlayın ve giriş/çıkış verilerini doğrulamak için (input validation) ek kontroller ekleyin. Yazılım güvenliği sorumluluğu geliştiriciye aittir.

Yorumlar (0)
Yorum Yaz