Repository Kalıbı
Coddy'nin PHP Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 81 / 91.
Repository Deseni, uygulamanızın iş mantığı ile veri depolama katmanı arasında aracılık eden bir tasarım desenidir. Verilerin gerçekte nasıl saklandığı veya getirildiğiyle ilgili ayrıntıları gizleyerek, domain nesnelerine erişmek için koleksiyon benzeri bir arayüz sağlar.
Bir repository'yi, nesneleri nasıl kalıcı hale getireceğini ve geri getireceğini bilen özelleşmiş bir koleksiyon olarak düşünün. Uygulama kodunuz, verilerin bir veritabanında mı, dosyada mı yoksa bir API'de mi olduğunu bilmeden, repository'den ID'ye göre bir kullanıcı ister veya yeni bir ürünü kaydeder. Bu ayrım, kodunuzu daha test edilebilir ve esnek hale getirir.
<?php
interface UserRepositoryInterface {
public function find(int $id): ?User;
public function findAll(): array;
public function save(User $user): void;
public function delete(int $id): void;
}
class User {
public function __construct(
public int $id,
public string $name,
public string $email
) {}
}
Repository uygulaması, gerçek depolama mekanizmasını yönetir:
<?php
class InMemoryUserRepository implements UserRepositoryInterface {
private array $users = [];
public function find(int $id): ?User {
return $this->users[$id] ?? null;
}
public function findAll(): array {
return array_values($this->users);
}
public function save(User $user): void {
$this->users[$user->id] = $user;
}
public function delete(int $id): void {
unset($this->users[$id]);
}
}
$repo = new InMemoryUserRepository();
$repo->save(new User(1, "Alice", "alice@example.com"));
$repo->save(new User(2, "Bob", "bob@example.com"));
echo $repo->find(1)->name . "\n";
echo count($repo->findAll());
Çıktı:
Alice
2Bu desenin güzelliği, iş mantığınızı değiştirmeden uygulamaları (implementations) değiştirebilmenizdir. Bellek içi depolamadan bir veritabanına geçmeniz mi gerekiyor? Aynı arayüzü (interface) uygulayan yeni bir repository sınıfı oluşturun. Uygulama kodunuz dokunulmadan kalır çünkü somut uygulamaya (concrete implementation) değil, arayüze (interface) bağlıdır.
Görev
KolayRepository Pattern kullanarak bir ürün envanter sistemi oluşturalım. Alan (domain) nesneleriniz ile bunların nasıl saklandığı arasında temiz bir ayrım oluşturacaksınız; bu da uygulama kodunuzun saklama detaylarını bilmeden ürünlerle çalışmasına olanak tanır.
Kodunuzu dört dosya halinde düzenleyeceksiniz:
Product.php— Envanterinizdeki öğeleri temsil eden birProductsınıfı oluşturun. Her ürünün birid(int),name(string) veprice(float) değeri vardır. Kolay erişim için genel (public) özelliklerle birlikte constructor promotion kullanın.ProductRepositoryInterface.php— Herhangi bir ürün saklama uygulaması için sözleşmeyi belirleyen birProductRepositoryInterfacetanımlayın. Arayüzünüz şu yöntemleri bildirmelidir:find(int $id): ?Product— Bir ürünü ID'ye göre getirir veya bulunamazsa null dönerfindAll(): array— Tüm ürünleri bir dizi olarak getirirsave(Product $product): void— Bir ürünü saklar veya güncellerdelete(int $id): void— Bir ürünü ID'ye göre siler
InMemoryProductRepository.php— Hem Product sınıfını hem de arayüzü dahil edin. Ürünleri saklamak için özel (private) bir dizi kullanan ve arayüzü uygulayan birInMemoryProductRepositorysınıfı oluşturun. Ürünler, verimli arama için ID'lerine göre dizinlenmelidir.findAll()yöntemi yalnızca ürün nesnelerini döndürmelidir (dizi anahtarlarını sıfırlamak içinarray_values()kullanın).main.php— Repository dosyasını dahil edin. İki girdi alacaksınız: önce eklenecek ürünlerin JSON dizesi, ardından ayrı bir satırda aranacak tam sayı ID.JSON formatı şu şekilde olacaktır:
[{"id": 1, "name": "Laptop", "price": 999.99}, {"id": 2, "name": "Mouse", "price": 29.99}]Bir
InMemoryProductRepositoryoluşturun, JSON girdisindeki tüm ürünleri kaydedin, ardından belirli bir ürünü bulmak için ikinci girdiyi (ID) kullanın. Sonuçları şu formatta yazdırın:Total products: [count] Found: [name] - $[price]Fiyatı iki ondalık basamak olacak şekilde biçimlendirin. Ürün bulunamazsa, bunun yerine
Found: Not foundyazdırın.
Repository Pattern, saklama uygulamalarını değiştirmeniz gerektiğinde parlar. Ana kodunuz yalnızca arayüzüne bağlıdır — bellek içi saklamadan bir veritabanına geçmek, herhangi bir uygulama mantığını değiştirmeden yeni bir repository sınıfı oluşturmak anlamına gelir.
Kendin dene
<?php
require_once 'InMemoryProductRepository.php';
// Girdiyi oku
$jsonInput = trim(fgets(STDIN));
$searchId = intval(trim(fgets(STDIN)));
// JSON girdisini bir diziye dönüştür
$productsData = (array)json_decode($jsonInput, true);
// TODO: Bir InMemoryProductRepository örneği oluştur
// TODO: $productsData üzerinde döngü kur ve her ürünü kaydet
// Her öğe 'id', 'name' ve 'price' anahtarlarına sahiptir
// TODO: Tüm ürünleri al ve toplam sayıyı yazdır
// Format: "Total products: [count]"
// TODO: $searchId ile ürünü bul
// Eğer bulunursa, yazdır: "Found: [name] - $[price]" (fiyat 2 ondalık basamaklı formatta)
// Eğer bulunamazsa, yazdır: "Found: Not found"
?>Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1OOP Temelleri
Harici DosyalarOOP'ye GirişSınıflar ve Nesneler$this Anahtar KelimesiMetotlarÖzelliklerYapıcı Metot (__construct)Yıkıcı Metot (__destruct)Özet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtımparent:: Anahtar KelimesiMetot Geçersiz Kılmafinal Anahtar KelimesiSoyut SınıflarÖzet - Çalışan Hiyerarşisi7Kapsülleme
Public, Protected, PrivateErişim Belirleyicilere Derinlemesine BakışGetter ve Setter MetotlarıBilgi GizlemeConstructor Promotion (8.0)Özet - Öğrenci Kayıt Sistemi10İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımDependency InjectionAnonim SınıflarEnum'lar (PHP 8.1)Fiber'lar (PHP 8.1)Nesne Klonlama: Derinlemesine İncelemeGenerator'lar ve Iterator'lar13Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıRepository Kalıbı2İsim Alanları ve Autoloading
İsim Alanlarına Girişuse Anahtar KelimesiPSR-4 Autoloading StandartıComposer AutoloaderÖzet - Düzenli Proje5Arayüzler ve Sözleşmeler
Arayüzlere GirişArayüzleri UygulamaBirden Fazla Arayüz UygulamaArayüz vs Soyut SınıfArayüzler ile Tip BelirlemeÖzet - Şekil Hesaplayıcı8Sihirli Metotlar
Sihirli Metotlara Giriş__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Nesne Klonlama__serialize & __unserializeÖzet - Özel Koleksiyon3Sınıf Özellikleri
Örnek ve Statik ÖzelliklerSınıflarda SabitlerStatik Metotlar ve ÖzelliklerPrivate ve Protected ÖzelliklerReadonly Özellikler (PHP 8.1)Özet - Banka Hesabı Yöneticisi6Çok Biçimlilik
Metot Geçersiz Kılmaya Yeniden BakışArayüzler ile Çok BiçimlilikType Hinting ve Union TypesLate Static BindingÖzet - Ödeme İşlemcisi9Trait'ler
Trait'lere GirişÇoklu Trait KullanımıTrait Çakışma ÇözümüTrait'lerde Soyut MetotlarTrait'ler ve Kalıtım12Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıObserver KalıbıStrategy Kalıbı15Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi