Peristiwa Domain dan Layanan Domain
Catat fakta bisnis dengan peristiwa dan layanan domain.
Peristiwa Domain dan Layanan Domain adalah pelajaran PHP Academy gratis di CoddyKit. Ini adalah pelajaran 3 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.
Mencatat fakta bisnis
Tidak semua perilaku cocok ditempatkan di dalam satu entitas. Peristiwa Domain mencatat fakta bisnis bermakna yang sudah terjadi (OrderPlaced), sehingga bagian lain dari sistem dapat merespons. Layanan Domain menampung logika domain yang secara alami tidak menjadi milik satu entitas atau objek nilai. Pelajaran ini menunjukkan cara keduanya menjaga model tetap ekspresif tanpa membuat agregat terlalu besar.
Apa itu Peristiwa Domain
Peristiwa Domain adalah catatan yang tidak dapat diubah tentang sesuatu yang terjadi di dalam domain, dinamai dalam bentuk lampau menggunakan bahasa yang digunakan bersama: OrderPlaced, PaymentReceived, CustomerRelocated. Peristiwa ini membawa data yang menjelaskan fakta tersebut serta waktu kejadiannya. Peristiwa ini merupakan objek nilai: dibuat sekali dan tidak pernah diubah.
<?php
final class OrderPlaced {
public function __construct(
public readonly string $orderId,
public readonly int $totalCents,
public readonly DateTimeImmutable $occurredOn = new DateTimeImmutable()
) {}
}
$e = new OrderPlaced('o1', 1300);
echo $e->orderId, ' @ ', $e->occurredOn->format('H:i'), PHP_EOL;
Agregat mencatat peristiwa
Akar agregat mencatat peristiwa sebagai bagian dari perilakunya, lalu menyediakannya agar lapisan aplikasi dapat mengirimkannya setelah transaksi dikonfirmasi. Agregat itu sendiri tidak mengirimkan peristiwa — agregat hanya mencatat. Hal ini menjaga domain tetap bebas dari urusan infrastruktur.
<?php
final class OrderPlaced {
public function __construct(public readonly string $orderId) {}
}
abstract class AggregateRoot {
private array $events = [];
protected function record(object $e): void { $this->events[] = $e; }
public function releaseEvents(): array {
$out = $this->events; $this->events = []; return $out;
}
}
final class Order extends AggregateRoot {
public function __construct(public readonly string $id) {
$this->record(new OrderPlaced($id));
}
}
$o = new Order('o1');
foreach ($o->releaseEvents() as $e) { echo get_class($e), PHP_EOL; }
Kirim setelah konfirmasi
Layanan aplikasi menyimpan agregat, mengonfirmasi transaksi, lalu mengirimkan peristiwa yang dikeluarkan. Pengiriman setelah konfirmasi memastikan penangan tidak pernah merespons fakta yang kemudian dibatalkan. Urutan di bawah ini adalah templat aman untuk efek samping seperti email atau panggilan eksternal.
<?php
final class PlaceOrderService {
public function __construct(
private object $repo,
private object $dispatcher
) {}
public function handle(object $order): void {
// 1. persist inside a transaction
$this->repo->save($order); // commit happens here
// 2. only AFTER commit, release and dispatch
foreach ($order->releaseEvents() as $event) {
$this->dispatcher->dispatch($event);
}
}
}
echo "order persisted, then events dispatched", PHP_EOL;
Penangan merespons
Setiap peristiwa dapat memiliki banyak penangan yang tidak bergantung pada agregat yang memicunya. Pengirim PSR-14 meneruskan peristiwa kepada pendengar yang terdaftar. Menambahkan reaksi baru (analitik, pemberitahuan) berarti menambahkan pendengar, bukan mengubah agregat.
<?php
final class OrderPlaced { public function __construct(public readonly string $orderId) {} }
final class Dispatcher {
private array $listeners = [];
public function on(string $event, callable $l): void { $this->listeners[$event][] = $l; }
public function dispatch(object $event): void {
foreach ($this->listeners[$event::class] ?? [] as $l) { $l($event); }
}
}
$d = new Dispatcher();
$d->on(OrderPlaced::class, fn($e) => print("email for {$e->orderId}\n"));
$d->on(OrderPlaced::class, fn($e) => print("analytics for {$e->orderId}\n"));
$d->dispatch(new OrderPlaced('o1'));
Peristiwa lintas batas
Peristiwa domain memisahkan agregat yang harus tetap konsisten tanpa berbagi transaksi. OrderPlaced dalam konteks Penjualan dapat memicu reservasi inventaris dalam konteks lain melalui sebuah peristiwa. Di dalam sistem, peristiwa tersebut berupa objek; lintas layanan, peristiwa tersebut sering menjadi peristiwa integrasi pada perantara pesan. Bedakan peristiwa domain internal dan peristiwa integrasi eksternal — kontrak publik tidak seharusnya menjadi model internal Anda.
Apa itu Layanan Domain
Layanan Domain menampung logika domain yang:
- melibatkan beberapa agregat atau entitas, sehingga tidak cocok ditempatkan di salah satunya, dan
- merupakan konsep domain yang nyata, yang dinyatakan dalam bahasa yang digunakan bersama.
Layanan ini tidak memiliki status dan beroperasi pada objek domain. Layanan FundsTransfer yang mendebit satu akun dan mengkredit akun lain adalah contoh klasiknya.
Layanan Domain dalam kode
Layanan ini mengoordinasikan dua agregat, tetapi tidak menyimpan statusnya sendiri. Logika tersebut bukan milik salah satu akun, sehingga ditempatkan dalam layanan yang dinamai sesuai operasi domain.
<?php
final class Account {
public function __construct(public readonly string $id, private int $cents) {}
public function withdraw(int $c): void {
if ($c > $this->cents) { throw new DomainException('insufficient funds'); }
$this->cents -= $c;
}
public function deposit(int $c): void { $this->cents += $c; }
public function balance(): int { return $this->cents; }
}
final class MoneyTransferService {
public function transfer(Account $from, Account $to, int $cents): void {
$from->withdraw($cents);
$to->deposit($cents);
}
}
$a = new Account('a', 1000); $b = new Account('b', 0);
(new MoneyTransferService())->transfer($a, $b, 400);
echo $a->balance(), '/', $b->balance(), PHP_EOL; // 600/400
Layanan Domain vs Layanan Aplikasi
Jangan tertukar antara keduanya:
- Layanan Domain berisi logika bisnis dan berada di lapisan domain; layanan ini tidak mengetahui apa pun tentang transaksi atau HTTP.
- Layanan Aplikasi mengatur sebuah kasus penggunaan: memuat agregat dari repositori, memanggil logika domain, mengonfirmasi transaksi, dan mengirimkan peristiwa. Layanan ini merupakan koordinator tipis tanpa aturan bisnisnya sendiri.
Hindari jebakan layanan
Layanan domain mudah digunakan secara berlebihan. Jika logika dapat ditempatkan pada entitas atau objek nilai, logika tersebut seharusnya ditempatkan di sana: itulah cara menghindari model anemia. Gunakan layanan domain hanya ketika operasi benar-benar mencakup beberapa agregat atau tidak memiliki tempat alami. Jika tidak, Anda akan mengeluarkan perilaku dari entitas dan menciptakan kembali kode prosedural.
Layanan aplikasi melakukan koordinasi
Menyatukan semuanya: layanan aplikasi yang tipis mengambil agregat dari repositori, memanggil layanan domain untuk logika lintas agregat, menyimpan hasilnya, dan mengirimkan peristiwa. Isinya hanya orkestrasi — tanpa aturan bisnisnya sendiri.
<?php
final class Account {
public function __construct(public readonly string $id, public int $cents) {}
}
final class MoneyTransferService { // domain service: the rule
public function transfer(Account $from, Account $to, int $c): void {
if ($c > $from->cents) { throw new DomainException('insufficient'); }
$from->cents -= $c; $to->cents += $c;
}
}
final class TransferApp { // application service: orchestration only
public function __construct(private MoneyTransferService $domain) {}
public function run(Account $a, Account $b, int $c): void {
$this->domain->transfer($a, $b, $c); // then repo->save + dispatch
}
}
$a = new Account('a', 1000); $b = new Account('b', 0);
(new TransferApp(new MoneyTransferService()))->run($a, $b, 250);
echo $a->cents, '/', $b->cents, PHP_EOL; // 750/250
Pemeriksaan Cepat
Peristiwa dan layanan.
Rangkuman
Anda telah menangkap fakta bisnis dan logika yang belum memiliki tempat yang tepat. Peristiwa Domain adalah catatan tak dapat diubah yang ditulis dalam bentuk lampau, yang dicatat oleh agregat dan dikirimkan setelah komit oleh lapisan aplikasi. Hal ini melepaskan keterikatan reaksi dan memungkinkan peristiwa melintasi batas agregat. Layanan Domain menampung logika domain tanpa status yang mencakup beberapa agregat, berbeda dari layanan aplikasi yang tipis dan hanya mengorkestrasi kasus penggunaan. Gunakan keduanya secara terbatas agar perilaku tetap berada pada entitas dan objek nilai di tempat yang semestinya.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Peristiwa Domain dan Layanan Domain” gratis?
Ya — teks lengkap “Peristiwa Domain dan Layanan Domain” 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 “Peristiwa Domain dan Layanan Domain”?
Catat fakta bisnis dengan peristiwa dan layanan domain. 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 3 dari 4.
Berapa lama pelajaran “Peristiwa Domain dan Layanan Domain” 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