Membangun Sistem Cart dengan Konsep SOLID di PHP

Contoh penerapan prinsip SOLID dalam OOP dengan PHP, menggunakan kasus Cart
Written by @kiosmerdeka

Dalam dunia pemrograman berorientasi objek (OOP), konsep SOLID sangat penting untuk menghasilkan kode yang bersih, mudah dipelihara, dan fleksibel terhadap perubahan. Pada artikel ini, kita akan membangun sistem keranjang belanja (Cart) sederhana dengan menerapkan prinsip SOLID menggunakan bahasa PHP native.

Apa itu SOLID?

SOLID adalah akronim dari lima prinsip desain dalam OOP:

  1. S – Single Responsibility Principle (SRP)
  2. O – Open/Closed Principle (OCP)
  3. L – Liskov Substitution Principle (LSP)
  4. I – Interface Segregation Principle (ISP)
  5. D – Dependency Inversion Principle (DIP)

Dengan menggunakan kasus cart, kita akan membangun aplikasi yang mematuhi prinsip-prinsip ini.

Struktur Folder Project

/cart-project
|-- index.php
|-- classes/
    |-- Cart.php
    |-- CartItem.php
    |-- Discount.php
    |-- PercentageDiscount.php
    |-- FixedDiscount.php
    |-- CartService.php
    |-- Exportable.php
    |-- JsonCartExporter.php
    |-- CsvCartExporter.php

1. Single Responsibility Principle (SRP)

Setiap class harus hanya memiliki satu tanggung jawab.

  • CartItem.php hanya bertugas merepresentasikan item di keranjang.
  • Cart.php hanya bertugas menyimpan dan mengelola item-item tersebut.
class CartItem {
    public function __construct(
        private string $name,
        private float $price,
        private int $quantity
    ) {}

    public function getTotal(): float {
        return $this->price * $this->quantity;
    }

    public function toArray(): array {
        return [
            'name' => $this->name,
            'price' => $this->price,
            'quantity' => $this->quantity,
            'total' => $this->getTotal(),
        ];
    }
}
class Cart {
    private array $items = [];

    public function addItem(CartItem $item): void {
        $this->items[] = $item;
    }

    public function getItems(): array {
        return $this->items;
    }

    public function getTotal(): float {
        return array_reduce($this->items, fn($sum, $item) => $sum + $item->getTotal(), 0);
    }

    public function getItemsAsArray(): array {
        return array_map(fn($item) => $item->toArray(), $this->items);
    }
}

2. Open/Closed Principle (OCP)

Kode harus terbuka untuk ekstensi, tapi tertutup untuk modifikasi. Kita bisa membuat diskon dengan berbagai strategi tanpa mengubah kode lama.

interface Discount {
    public function apply(float $total): float;
}

class PercentageDiscount implements Discount {
    public function __construct(private float $percentage) {}

    public function apply(float $total): float {
        return $total - ($total * $this->percentage);
    }
}

class FixedDiscount implements Discount {
    public function __construct(private float $amount) {}

    public function apply(float $total): float {
        return max(0, $total - $this->amount);
    }
}

3. Liskov Substitution Principle (LSP)

Setiap turunan class atau implementasi interface harus bisa menggantikan parent-nya tanpa merusak program.

Baca juga  Python Unable To Create Virtual Environment

Fungsi ini bisa menerima diskon tipe apapun karena semuanya implementasi dari interface Discount:

function applyDiscount(Cart $cart, Discount $discount): float {
    return $discount->apply($cart->getTotal());
}

4. Interface Segregation Principle (ISP)

Jangan memaksa class untuk mengimplementasikan method yang tidak dibutuhkan. Kita buat interface khusus untuk ekspor data:

interface Exportable {
    public function export(): string;
}

class JsonCartExporter implements Exportable {
    public function __construct(private Cart $cart) {}

    public function export(): string {
        return json_encode($this->cart->getItemsAsArray(), JSON_PRETTY_PRINT);
    }
}

class CsvCartExporter implements Exportable {
    public function export(): string {
        $items = $this->cart->getItemsAsArray();
        $csv = "name,price,quantity,total\n";
        foreach ($items as $item) {
            $csv .= "{$item['name']},{$item['price']},{$item['quantity']},{$item['total']}\n";
        }
        return $csv;
    }
}

5. Dependency Inversion Principle (DIP)

Kelas CartService bergantung pada abstraksi, bukan implementasi konkrit.

class CartService {
    public function __construct(
        private Cart $cart,
        private Discount $discount
    ) {}

    public function checkoutTotal(): float {
        return $this->discount->apply($this->cart->getTotal());
    }
}

Main Script (index.php)

require_once 'classes/CartItem.php';
require_once 'classes/Cart.php';
require_once 'classes/PercentageDiscount.php';
require_once 'classes/FixedDiscount.php';
require_once 'classes/CartService.php';
require_once 'classes/JsonCartExporter.php';
require_once 'classes/CsvCartExporter.php';

$cart = new Cart();
$cart->addItem(new CartItem("Keyboard", 250000, 1));
$cart->addItem(new CartItem("Mouse", 100000, 2));

$discount = new PercentageDiscount(0.1); // 10% diskon

$service = new CartService($cart, $discount);
$total = $service->checkoutTotal();

echo "Total setelah diskon: Rp " . number_format($total, 0, ',', '.') . "\n\n";

$exporter = new JsonCartExporter($cart);
echo "Export JSON:\n";
echo $exporter->export();

echo "\n\nExport CSV:\n";
$csvExporter = new CsvCartExporter($cart);
echo $csvExporter->export();

Penutup

Dengan mengikuti prinsip SOLID, kita bisa membuat sistem Cart yang modular, mudah diperluas, dan mudah dirawat. Kamu bisa dengan mudah menambahkan jenis diskon baru atau format ekspor lain tanpa menyentuh kode yang sudah ada. Prinsip-prinsip ini membantu menjaga kualitas dan skalabilitas project seiring berkembangnya kebutuhan.

Keywords: SOLID OOP PHP, Sistem Cart PHP, Studi Kasus SOLID PHP, Single Responsibility Principle PHP, Open Closed Principle contoh, Liskov Substitution PHP, Interface Segregation Principle, Dependency Inversion PHP, Cart system PHP native, Belajar OOP PHP

Leave a Comment