Agregat, Repositori, dan Factory
Lindungi invarian dengan agregat dan simpan secara rapi.
Agregat, Repositori, dan Factory adalah pelajaran PHP Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar PHP Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus PHP Academy mencakup 4 pelajaran total.
Melindungi invarian
Setelah memiliki entitas dan objek nilai, Anda memerlukan pola untuk menjaga agar kelompok objek tersebut tetap konsisten dan tersimpan dengan baik. DDD menjawabnya dengan tiga pola taktis: Agregat (batas konsistensi), Repositori (abstraksi persistensi yang menyerupai koleksi), dan Pabrik (untuk pembuatan yang kompleks). Pelajaran ini menunjukkan cara ketiganya bekerja sama dalam PHP.
Apa itu Agregat
Agregat adalah kelompok entitas dan objek nilai yang diperlakukan sebagai satu unit untuk perubahan data. Salah satu entitas menjadi Akar Agregat — satu-satunya anggota yang boleh dirujuk oleh kode di luar. Semua perubahan dilakukan melalui akar, yang menegakkan invarian agregat. Agregat juga merupakan batas transaksi: agregat dimuat dan disimpan secara atomik.
Akar menjaga keseluruhan
Pemanggil dari luar tidak pernah menyentuh anggota bagian dalam secara langsung. Untuk menambahkan item baris, Anda memanggil metode pada akar, yang memvalidasi dan menjaga konsistensi (total, batas). Dengan demikian, invarian tetap berada di satu tempat.
<?php
final class LineItem {
public function __construct(
public readonly string $sku,
public readonly int $qty,
public readonly int $unitCents
) {}
public function subtotal(): int { return $this->qty * $this->unitCents; }
}
final class Order { // Aggregate Root
/** @var LineItem[] */
private array $items = [];
public function __construct(public readonly string $id) {}
public function addItem(string $sku, int $qty, int $unitCents): void {
if ($qty < 1) { throw new DomainException('qty must be >= 1'); }
$this->items[] = new LineItem($sku, $qty, $unitCents);
}
public function total(): int {
return array_sum(array_map(fn(LineItem $i) => $i->subtotal(), $this->items));
}
}
$o = new Order('o1');
$o->addItem('A', 2, 500);
$o->addItem('B', 1, 300);
echo $o->total(), PHP_EOL; // 1300
Merancang agregat kecil
Kesalahan yang sering terjadi adalah membuat agregat terlalu besar (Order yang juga memiliki seluruh grafik Customer). Aturan praktisnya:
- Jaga agar agregat tetap kecil; rujuk agregat lain berdasarkan id, bukan dengan menyimpan objeknya.
- Satu transaksi seharusnya mengubah satu agregat; koordinasikan perubahan lintas agregat dengan peristiwa domain.
- Invarian yang harus selalu terpenuhi menentukan batasnya.
Merujuk berdasarkan pengidentifikasi
Pesanan menyimpan objek nilai customerId, bukan entitas Customer. Hal ini menjaga batas konsistensi tetap rapat dan menghindari pemuatan graf objek yang besar. Konsistensi lintas agregat menjadi konsistensi bertahap, yang ditangani oleh peristiwa, bukan satu transaksi raksasa.
<?php
final class CustomerId {
public function __construct(public readonly string $value) {}
}
final class Order {
public function __construct(
public readonly string $id,
public readonly CustomerId $customerId // reference, not object
) {}
}
$order = new Order('o1', new CustomerId('cus_99'));
echo $order->customerId->value, PHP_EOL;
Kontrak Repositori
Repositori memberikan ilusi berupa koleksi akar agregat di dalam memori. Domain hanya bergantung pada antarmuka; implementasinya (Doctrine, PDO, atau di dalam memori) berada di lapisan infrastruktur. Repositori menangani agregat utuh, tidak pernah baris yang sebagian.
<?php
interface OrderRepository {
public function ofId(string $id): ?Order;
public function save(Order $order): void;
public function nextIdentity(): string;
}
Implementasi di dalam memori
Repositori di dalam memori sangat berguna untuk pengujian unit yang cepat tanpa database. Karena domain bergantung pada antarmuka, Anda dapat menukar implementasi dengan bebas (Pembalikan Dependensi dalam praktik).
<?php
interface OrderRepository {
public function ofId(string $id): ?object;
public function save(object $order): void;
public function nextIdentity(): string;
}
final class Order { public function __construct(public readonly string $id) {} }
final class InMemoryOrderRepository implements OrderRepository {
private array $store = [];
public function ofId(string $id): ?object { return $this->store[$id] ?? null; }
public function save(object $order): void { $this->store[$order->id] = $order; }
public function nextIdentity(): string { return 'o_' . bin2hex(random_bytes(4)); }
}
$repo = new InMemoryOrderRepository();
$repo->save(new Order('o1'));
var_dump($repo->ofId('o1') !== null);
Repositori bukan DAO
Repositori bukan DAO generik untuk operasi buat, baca, perbarui, dan hapus. Repositori menyediakan kueri yang bermakna bagi domain (findOverdueOrders()) dan membentuk kembali agregat utuh dengan invarian yang tetap terjaga. Repositori sengaja menyembunyikan detail SQL dan ORM agar domain tetap tidak bergantung pada persistensi. Hindari membocorkan pembangun kueri atau metode generik save($anyEntity) ke dalam domain.
Pabrik untuk pembuatan kompleks
Jika pembuatan agregat melibatkan logika nyata — membuat identitas, menyusun objek nilai, dan menegakkan invarian saat pembuatan — pindahkan proses tersebut ke dalam Pabrik (kelas khusus atau konstruktor bernama statis). Dengan demikian, konstruktor entitas tetap jujur dan aturan pembuatan yang valid terpusat.
<?php
final class Order {
private function __construct(
public readonly string $id,
public readonly string $customerId
) {}
public static function place(string $customerId): self {
if ($customerId === '') { throw new DomainException('customer required'); }
return new self('o_' . bin2hex(random_bytes(4)), $customerId);
}
}
$order = Order::place('cus_1');
echo $order->id, PHP_EOL;
Cara ketiganya bekerja sama
Alur umum dalam layanan aplikasi:
- Pabrik (atau konstruktor bernama) membuat agregat yang valid.
- Metode akar agregat menegakkan invarian selama penggunaan.
- Repositori menyimpan dan kemudian membentuk kembali agregat secara utuh.
Layanan aplikasi mengatur semuanya dalam satu transaksi untuk setiap agregat, dengan hanya bergantung pada antarmuka.
Menegakkan invarian seluruh agregat
Nilai sebenarnya dari akar adalah menegakkan invarian yang mencakup beberapa anggota. Di sini, pesanan menolak item baris jika item tersebut akan membuat total melampaui batas kredit — aturan yang tidak dapat ditegakkan oleh satu LineItem saja. Karena semua perubahan dilakukan melalui akar, aturan tersebut tidak pernah dapat dilewati.
<?php
final class Order {
private array $items = [];
public function __construct(
public readonly string $id,
private int $creditLimitCents
) {}
public function addItem(int $cents): void {
if ($this->total() + $cents > $this->creditLimitCents) {
throw new DomainException('Exceeds credit limit');
}
$this->items[] = $cents;
}
public function total(): int { return array_sum($this->items); }
}
$o = new Order('o1', 1000);
$o->addItem(600);
try { $o->addItem(600); } catch (DomainException $e) { echo $e->getMessage(), PHP_EOL; }
echo $o->total(), PHP_EOL; // 600
Pemeriksaan Singkat
Perancangan agregat.
Ringkasan
Anda telah mempelajari cara melindungi invarian dan menyimpan data dengan baik. Agregat membentuk batas konsistensi dan transaksi, hanya diubah melalui akarnya, serta dijaga tetap kecil dengan merujuk agregat lain berdasarkan pengidentifikasi. Repositori menyajikan akar agregat sebagai koleksi di balik antarmuka domain, menyembunyikan ORM/SQL dan memungkinkan penggunaan objek pengganti untuk pengujian di dalam memori. Pabrik memusatkan pembuatan kompleks yang menegakkan invarian. Bersama-sama, ketiganya menjaga model domain tetap konsisten dan tidak bergantung pada persistensi.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Agregat, Repositori, dan Factory” gratis?
Ya — teks lengkap “Agregat, Repositori, dan Factory” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus PHP Academy, upgrade ke CoddyKit PRO. Kursus PHP Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Agregat, Repositori, dan Factory”?
Lindungi invarian dengan agregat dan simpan secara rapi. Kamu berlatih PHP Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai PHP Academy?
Tidak diperlukan pengalaman sebelumnya. PHP Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “Agregat, Repositori, dan Factory” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran PHP Academy ini?
Ya. Setiap pelajaran PHP Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Blok Bangunan DDD: Entitas dan Objek Nilai
- Agregat, Repositori, dan Factory
- Peristiwa Domain dan Layanan Domain
- Konteks Terbatas dan Pemetaan Konteks