Unit 5: Mengimplementasikan Pemrograman Terstruktur

Mempelajari konsep pemrograman terstruktur, koneksi database MySQL, dan implementasi operasi CRUD untuk aplikasi web dinamis.

Estimasi: 12 Jam 3 Sub Materi

Tujuan Pembelajaran

  • Memahami konsep pemrograman terstruktur
  • Menguasai operasi CRUD database
  • Koneksi PHP-MySQL yang aman
  • Error handling dan debugging
Mulai dari Mana?

Untuk pemula yang baru belajar database, ikuti urutan ini:

Fundamental
Database Fundamental

Memahami konsep database dari dasar, struktur database, SQL, dan CRUD dengan analogi yang mudah dipahami.

  • Apa itu Database?
  • Struktur Database
  • Pengenalan SQL
  • Mengenal MySQL
  • 4 Quiz Interaktif
Durasi: 2 jam Mulai
Setup
Setup Database MySQL

Panduan lengkap instalasi XAMPP, konfigurasi MySQL, dan setup database siap pakai dengan 7 langkah mudah.

  • Download & Install XAMPP
  • Start Apache & MySQL
  • Akses phpMyAdmin
  • Create Database & Table
  • Test Koneksi PHP
Durasi: 1 jam Mulai
Praktik
CRUD Operations

Tutorial implementasi Create, Read, Update, Delete dengan PHP & MySQL lengkap dengan code yang bisa langsung digunakan.

  • CREATE - Tambah Data
  • READ - Tampil Data
  • UPDATE - Edit Data
  • DELETE - Hapus Data
  • Best Practices
Durasi: 3 jam Mulai

1. Struktur Program & Debugging

Pemrograman Terstruktur

Pemrograman terstruktur menggunakan tiga struktur kontrol dasar: sequence, selection, dan iteration.

Sequence

Eksekusi berurutan dari atas ke bawah

Selection

Percabangan dengan if/else/switch

Iteration

Perulangan dengan for/while/foreach

Fungsi dan Prosedur
<?php
// Fungsi dengan return value
function calculateDiscount($price, $discountPercent) {
    if ($discountPercent < 0 || $discountPercent > 100) {
        throw new InvalidArgumentException('Discount must be between 0 and 100');
    }
    
    return $price * ($discountPercent / 100);
}

// Prosedur (void function)
function displayProductInfo($product) {
    echo "<div class='product'>";
    echo "<h3>" . htmlspecialchars($product['name']) . "</h3>";
    echo "<p>Price: $" . number_format($product['price'], 2) . "</p>";
    echo "</div>";
}

// Fungsi dengan multiple parameters dan default values
function formatCurrency($amount, $currency = 'USD', $decimals = 2) {
    $symbols = [
        'USD' => '$',
        'EUR' => '€',
        'IDR' => 'Rp'
    ];
    
    $symbol = $symbols[$currency] ?? $currency;
    return $symbol . number_format($amount, $decimals);
}

// Usage examples
try {
    $originalPrice = 100;
    $discountAmount = calculateDiscount($originalPrice, 15);
    $finalPrice = $originalPrice - $discountAmount;
    
    $product = [
        'name' => 'Laptop Gaming',
        'price' => $finalPrice
    ];
    
    displayProductInfo($product);
    echo formatCurrency($finalPrice, 'IDR');
    
} catch (Exception $e) {
    error_log($e->getMessage());
    echo "An error occurred while processing the product.";
}
?>
Error Handling dan Debugging
PHP Error Handling
<?php
// Try-catch block
try {
    $result = riskyOperation();
    processResult($result);
} catch (DatabaseException $e) {
    error_log("Database error: " . $e->getMessage());
    showUserError("Database temporarily unavailable");
} catch (ValidationException $e) {
    showUserError($e->getMessage());
} catch (Exception $e) {
    error_log("Unexpected error: " . $e->getMessage());
    showUserError("An unexpected error occurred");
}

// Custom error handler
function customErrorHandler($errno, $errstr, $errfile, $errline) {
    error_log("Error [$errno]: $errstr in $errfile on line $errline");
}
set_error_handler('customErrorHandler');

// Debug functions
function debugVariable($var, $label = '') {
    echo "<pre>";
    if ($label) echo "<strong>$label:</strong>\n";
    var_dump($var);
    echo "</pre>";
}
?>
JavaScript Debugging
// Console debugging methods
console.log('Basic logging');
console.error('Error message');
console.warn('Warning message');
console.info('Info message');

// Object inspection
const user = {name: 'John', age: 30};
console.table(user);

// Performance timing
console.time('operation');
// ... some operation
console.timeEnd('operation');

// Try-catch for JavaScript
function safeOperation() {
    try {
        const result = JSON.parse(responseData);
        return processData(result);
    } catch (error) {
        console.error('JSON parse error:', error.message);
        showUserMessage('Invalid data received');
        return null;
    }
}

// Debug helper function
function debug(variable, label = '') {
    if (typeof variable === 'object') {
        console.group(label || 'Debug Object');
        console.table(variable);
        console.groupEnd();
    } else {
        console.log(label + ':', variable);
    }
}

2. Database MySQL & Koneksi PHP

Dasar SQL

Structured Query Language (SQL) adalah bahasa standar untuk mengelola database relational.

Membuat Database dan Tabel
-- Membuat database
CREATE DATABASE db_mahasiswa;
USE db_mahasiswa;

-- Membuat tabel mahasiswa
CREATE TABLE mahasiswa (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nim VARCHAR(20) NOT NULL UNIQUE,
    nama VARCHAR(100) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    jurusan VARCHAR(50) NOT NULL,
    angkatan YEAR NOT NULL,
    alamat TEXT,
    tanggal_daftar TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    status ENUM('aktif', 'cuti', 'lulus', 'dropout') DEFAULT 'aktif'
);

-- Menambahkan index untuk performa
CREATE INDEX idx_jurusan ON mahasiswa(jurusan);
CREATE INDEX idx_angkatan ON mahasiswa(angkatan);

-- Contoh data sample
INSERT INTO mahasiswa (nim, nama, email, jurusan, angkatan, alamat) VALUES
('2023001001', 'Ahmad Muyassar', 'ahmad@email.com', 'Informatika', 2023, 'Makassar'),
('2023001002', 'Siti Nurhaliza', 'siti@email.com', 'Sistem Informasi', 2023, 'Jakarta'),
('2022001001', 'Budi Santoso', 'budi@email.com', 'Informatika', 2022, 'Surabaya');
Query SQL Fundamental
SELECT Queries
-- Basic SELECT
SELECT * FROM mahasiswa;

-- SELECT dengan kondisi
SELECT nama, email FROM mahasiswa 
WHERE jurusan = 'Informatika';

-- SELECT dengan ORDER BY
SELECT * FROM mahasiswa 
ORDER BY nama ASC;

-- SELECT dengan LIMIT
SELECT * FROM mahasiswa 
LIMIT 10 OFFSET 0;

-- SELECT dengan COUNT
SELECT jurusan, COUNT(*) as total
FROM mahasiswa 
GROUP BY jurusan;

-- SELECT dengan JOIN (jika ada tabel lain)
SELECT m.nama, m.nim, n.nilai
FROM mahasiswa m
LEFT JOIN nilai n ON m.id = n.mahasiswa_id;
INSERT, UPDATE, DELETE
-- INSERT data baru
INSERT INTO mahasiswa (nim, nama, email, jurusan, angkatan)
VALUES ('2023001003', 'Andi Rahman', 'andi@email.com', 'Informatika', 2023);

-- UPDATE data existing
UPDATE mahasiswa 
SET alamat = 'Bandung', status = 'aktif'
WHERE nim = '2023001003';

-- DELETE data
DELETE FROM mahasiswa 
WHERE status = 'dropout';

-- UPDATE dengan kondisi multiple
UPDATE mahasiswa 
SET status = 'lulus' 
WHERE angkatan = 2020 AND jurusan = 'Informatika';

-- INSERT multiple rows
INSERT INTO mahasiswa (nim, nama, email, jurusan, angkatan) VALUES
('2023001004', 'Lisa Andriani', 'lisa@email.com', 'Sistem Informasi', 2023),
('2023001005', 'Rudi Hartono', 'rudi@email.com', 'Informatika', 2023);
Koneksi PHP-MySQL
<?php
// Database configuration
class DatabaseConfig {
    const HOST = 'localhost';
    const USERNAME = 'root';
    const PASSWORD = '';
    const DATABASE = 'db_mahasiswa';
    const CHARSET = 'utf8mb4';
}

// Database connection class
class Database {
    private $connection;
    
    public function __construct() {
        try {
            $dsn = "mysql:host=" . DatabaseConfig::HOST . 
                   ";dbname=" . DatabaseConfig::DATABASE . 
                   ";charset=" . DatabaseConfig::CHARSET;
            
            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
            ];
            
            $this->connection = new PDO($dsn, DatabaseConfig::USERNAME, DatabaseConfig::PASSWORD, $options);
            
        } catch (PDOException $e) {
            error_log("Database connection failed: " . $e->getMessage());
            throw new Exception("Database connection failed");
        }
    }
    
    public function getConnection() {
        return $this->connection;
    }
    
    // Prepared statement untuk keamanan
    public function query($sql, $params = []) {
        try {
            $stmt = $this->connection->prepare($sql);
            $stmt->execute($params);
            return $stmt;
        } catch (PDOException $e) {
            error_log("Query failed: " . $e->getMessage());
            throw new Exception("Query execution failed");
        }
    }
    
    // Get single row
    public function fetchOne($sql, $params = []) {
        $stmt = $this->query($sql, $params);
        return $stmt->fetch();
    }
    
    // Get multiple rows
    public function fetchAll($sql, $params = []) {
        $stmt = $this->query($sql, $params);
        return $stmt->fetchAll();
    }
    
    // Get last inserted ID
    public function lastInsertId() {
        return $this->connection->lastInsertId();
    }
}

// Usage example
try {
    $db = new Database();
    
    // Test connection
    $result = $db->fetchOne("SELECT 'Connection successful' as message");
    echo $result['message'];
    
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}
?>

3. CRUD Operations (Create, Read, Update, Delete)

Implementasi CRUD dengan PHP

CRUD adalah operasi dasar untuk mengelola data dalam aplikasi web.

Demo: Simple CRUD Operations
Mahasiswa Data
ID NIM Nama Jurusan Aksi
1 2023001001 Ahmad Muyassar Informatika
2 2023001002 Siti Nurhaliza Sistem Informasi
Form Input
PHP CRUD Class Implementation
<?php
class MahasiswaManager {
    private $db;
    
    public function __construct(Database $database) {
        $this->db = $database;
    }
    
    // CREATE - Tambah mahasiswa baru
    public function create($data) {
        try {
            // Validasi data
            $this->validateMahasiswaData($data);
            
            $sql = "INSERT INTO mahasiswa (nim, nama, email, jurusan, angkatan, alamat) 
                    VALUES (:nim, :nama, :email, :jurusan, :angkatan, :alamat)";
            
            $params = [
                ':nim' => $data['nim'],
                ':nama' => $data['nama'],
                ':email' => $data['email'],
                ':jurusan' => $data['jurusan'],
                ':angkatan' => $data['angkatan'],
                ':alamat' => $data['alamat'] ?? null
            ];
            
            $this->db->query($sql, $params);
            return $this->db->lastInsertId();
            
        } catch (Exception $e) {
            error_log("Create mahasiswa failed: " . $e->getMessage());
            throw new Exception("Gagal menambah data mahasiswa");
        }
    }
    
    // READ - Ambil data mahasiswa
    public function getAll($limit = 10, $offset = 0) {
        try {
            $sql = "SELECT * FROM mahasiswa ORDER BY nama ASC LIMIT :limit OFFSET :offset";
            $params = [':limit' => $limit, ':offset' => $offset];
            
            return $this->db->fetchAll($sql, $params);
            
        } catch (Exception $e) {
            error_log("Get all mahasiswa failed: " . $e->getMessage());
            throw new Exception("Gagal mengambil data mahasiswa");
        }
    }
    
    public function getById($id) {
        try {
            $sql = "SELECT * FROM mahasiswa WHERE id = :id";
            return $this->db->fetchOne($sql, [':id' => $id]);
            
        } catch (Exception $e) {
            error_log("Get mahasiswa by ID failed: " . $e->getMessage());
            throw new Exception("Gagal mengambil data mahasiswa");
        }
    }
    
    public function searchByName($name) {
        try {
            $sql = "SELECT * FROM mahasiswa WHERE nama LIKE :name ORDER BY nama ASC";
            $params = [':name' => '%' . $name . '%'];
            
            return $this->db->fetchAll($sql, $params);
            
        } catch (Exception $e) {
            error_log("Search mahasiswa failed: " . $e->getMessage());
            throw new Exception("Gagal mencari data mahasiswa");
        }
    }
    
    // UPDATE - Update data mahasiswa
    public function update($id, $data) {
        try {
            // Validasi data
            $this->validateMahasiswaData($data);
            
            $sql = "UPDATE mahasiswa SET 
                    nim = :nim, nama = :nama, email = :email, 
                    jurusan = :jurusan, angkatan = :angkatan, alamat = :alamat 
                    WHERE id = :id";
            
            $params = [
                ':id' => $id,
                ':nim' => $data['nim'],
                ':nama' => $data['nama'],
                ':email' => $data['email'],
                ':jurusan' => $data['jurusan'],
                ':angkatan' => $data['angkatan'],
                ':alamat' => $data['alamat'] ?? null
            ];
            
            $stmt = $this->db->query($sql, $params);
            return $stmt->rowCount() > 0;
            
        } catch (Exception $e) {
            error_log("Update mahasiswa failed: " . $e->getMessage());
            throw new Exception("Gagal mengupdate data mahasiswa");
        }
    }
    
    // DELETE - Hapus data mahasiswa
    public function delete($id) {
        try {
            $sql = "DELETE FROM mahasiswa WHERE id = :id";
            $stmt = $this->db->query($sql, [':id' => $id]);
            
            return $stmt->rowCount() > 0;
            
        } catch (Exception $e) {
            error_log("Delete mahasiswa failed: " . $e->getMessage());
            throw new Exception("Gagal menghapus data mahasiswa");
        }
    }
    
    // Validasi data mahasiswa
    private function validateMahasiswaData($data) {
        if (empty($data['nim']) || empty($data['nama']) || empty($data['email'])) {
            throw new InvalidArgumentException("NIM, Nama, dan Email wajib diisi");
        }
        
        if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException("Format email tidak valid");
        }
        
        if (!is_numeric($data['angkatan']) || $data['angkatan'] < 2000) {
            throw new InvalidArgumentException("Angkatan harus berupa tahun yang valid");
        }
    }
    
    // Get statistics
    public function getStatistics() {
        try {
            $sql = "SELECT 
                        COUNT(*) as total_mahasiswa,
                        COUNT(CASE WHEN status = 'aktif' THEN 1 END) as aktif,
                        COUNT(CASE WHEN status = 'lulus' THEN 1 END) as lulus,
                        jurusan,
                        COUNT(*) as jumlah_per_jurusan
                    FROM mahasiswa 
                    GROUP BY jurusan";
            
            return $this->db->fetchAll($sql);
            
        } catch (Exception $e) {
            error_log("Get statistics failed: " . $e->getMessage());
            throw new Exception("Gagal mengambil statistik");
        }
    }
}

// Usage example
try {
    $db = new Database();
    $mahasiswaManager = new MahasiswaManager($db);
    
    // Tambah mahasiswa baru
    $newMahasiswa = [
        'nim' => '2023001006',
        'nama' => 'Test User',
        'email' => 'test@email.com',
        'jurusan' => 'Informatika',
        'angkatan' => 2023,
        'alamat' => 'Test Address'
    ];
    
    $id = $mahasiswaManager->create($newMahasiswa);
    echo "Mahasiswa baru ditambahkan dengan ID: " . $id;
    
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}
?>
CRUD Best Practices:
  • Selalu gunakan prepared statements untuk mencegah SQL injection
  • Validasi semua input data sebelum menyimpan ke database
  • Implementasi error handling yang proper
  • Gunakan transaksi untuk operasi multiple
  • Tambahkan logging untuk debugging

Praktik Unit 5: Aplikasi CRUD Mahasiswa

Tugas Praktik:
  1. Buat database dan tabel mahasiswa
  2. Implementasi class Database dan MahasiswaManager
  3. Buat interface web untuk CRUD operations
  4. Tambah fitur pencarian dan pagination
Schema Database
-- SQL untuk membuat database lengkap
CREATE DATABASE IF NOT EXISTS db_mahasiswa CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE db_mahasiswa;

CREATE TABLE mahasiswa (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nim VARCHAR(20) NOT NULL UNIQUE,
    nama VARCHAR(100) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    jurusan ENUM('Informatika', 'Sistem Informasi', 'Teknik Komputer') NOT NULL,
    angkatan YEAR NOT NULL,
    alamat TEXT,
    telepon VARCHAR(15),
    status ENUM('aktif', 'cuti', 'lulus', 'dropout') DEFAULT 'aktif',
    tanggal_daftar TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    tanggal_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Indexes untuk performa
CREATE INDEX idx_nama ON mahasiswa(nama);
CREATE INDEX idx_jurusan ON mahasiswa(jurusan);
CREATE INDEX idx_angkatan ON mahasiswa(angkatan);
CREATE INDEX idx_status ON mahasiswa(status);

-- Sample data
INSERT INTO mahasiswa (nim, nama, email, jurusan, angkatan, alamat, telepon) VALUES
('2023001001', 'Ahmad Muyassar Ibrahim', 'ahmad.muyassar@email.com', 'Informatika', 2023, 'Jl. Veteran No. 123, Makassar', '081234567890'),
('2023002001', 'Siti Nurhaliza Putri', 'siti.nurhaliza@email.com', 'Sistem Informasi', 2023, 'Jl. Sudirman No. 456, Jakarta', '081234567891'),
('2022001001', 'Budi Santoso', 'budi.santoso@email.com', 'Informatika', 2022, 'Jl. Thamrin No. 789, Surabaya', '081234567892'),
('2022002001', 'Lisa Andriani', 'lisa.andriani@email.com', 'Sistem Informasi', 2022, 'Jl. Gatot Subroto No. 321, Bandung', '081234567893'),
('2021001001', 'Rudi Hartono', 'rudi.hartono@email.com', 'Teknik Komputer', 2021, 'Jl. Ahmad Yani No. 654, Yogyakarta', '081234567894');
Template: API Endpoints
<?php
// api/mahasiswa.php - RESTful API endpoint
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type');

require_once '../includes/Database.php';
require_once '../includes/MahasiswaManager.php';

try {
    $db = new Database();
    $mahasiswaManager = new MahasiswaManager($db);
    
    $method = $_SERVER['REQUEST_METHOD'];
    $input = json_decode(file_get_contents('php://input'), true);
    
    switch ($method) {
        case 'GET':
            if (isset($_GET['id'])) {
                // Get single mahasiswa
                $mahasiswa = $mahasiswaManager->getById($_GET['id']);
                echo json_encode(['success' => true, 'data' => $mahasiswa]);
            } elseif (isset($_GET['search'])) {
                // Search mahasiswa
                $results = $mahasiswaManager->searchByName($_GET['search']);
                echo json_encode(['success' => true, 'data' => $results]);
            } else {
                // Get all mahasiswa with pagination
                $limit = $_GET['limit'] ?? 10;
                $offset = $_GET['offset'] ?? 0;
                $mahasiswa = $mahasiswaManager->getAll($limit, $offset);
                echo json_encode(['success' => true, 'data' => $mahasiswa]);
            }
            break;
            
        case 'POST':
            // Create new mahasiswa
            $id = $mahasiswaManager->create($input);
            echo json_encode(['success' => true, 'id' => $id, 'message' => 'Mahasiswa berhasil ditambahkan']);
            break;
            
        case 'PUT':
            // Update mahasiswa
            if (!isset($_GET['id'])) {
                throw new Exception('ID mahasiswa diperlukan untuk update');
            }
            $updated = $mahasiswaManager->update($_GET['id'], $input);
            if ($updated) {
                echo json_encode(['success' => true, 'message' => 'Mahasiswa berhasil diupdate']);
            } else {
                echo json_encode(['success' => false, 'message' => 'Data tidak ditemukan']);
            }
            break;
            
        case 'DELETE':
            // Delete mahasiswa
            if (!isset($_GET['id'])) {
                throw new Exception('ID mahasiswa diperlukan untuk delete');
            }
            $deleted = $mahasiswaManager->delete($_GET['id']);
            if ($deleted) {
                echo json_encode(['success' => true, 'message' => 'Mahasiswa berhasil dihapus']);
            } else {
                echo json_encode(['success' => false, 'message' => 'Data tidak ditemukan']);
            }
            break;
            
        default:
            throw new Exception('Method tidak didukung');
    }
    
} catch (Exception $e) {
    http_response_code(500);
    echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
?>