# DatabaseService Usage Examples This document shows how to refactor existing code to use the new `DatabaseService` class for cleaner, more maintainable database operations. ## Current State Files are using the procedural MySQLi pattern: ```php $stmt = $conn->prepare("SELECT * FROM users WHERE email = ?"); $stmt->bind_param("s", $email); $stmt->execute(); $result = $stmt->get_result(); $row = $result->fetch_assoc(); $stmt->close(); ``` ## Example 1: Simple SELECT (admin_members.php) ### Current Code ```php $stmt = $conn->prepare("SELECT user_id, first_name, last_name, tel_cell, email, dob, accept_indemnity FROM membership_application"); $stmt->execute(); $result = $stmt->get_result(); // Then in HTML/JS loop: while ($row = $result->fetch_assoc()) { // display row } ``` ### Using DatabaseService ```php // Simple - get all records $members = $db->select("SELECT user_id, first_name, last_name, tel_cell, email, dob, accept_indemnity FROM membership_application"); // In HTML/JS loop: foreach ($members as $row) { // display row } ``` **Benefits:** - No manual `bind_param()`, `execute()`, `close()` needed - Returns array directly - Automatic error tracking via `$db->getLastError()` --- ## Example 2: SELECT with Parameters (validate_login.php) ### Current Code ```php $query = "SELECT * FROM users WHERE email = ?"; $stmt = $conn->prepare($query); $stmt->bind_param("s", $email); $stmt->execute(); $result = $stmt->get_result(); if ($result->num_rows == 1) { $row = $result->fetch_assoc(); // use $row } $stmt->close(); ``` ### Using DatabaseService ```php $user = $db->selectOne( "SELECT * FROM users WHERE email = ?", [$email], "s" // s = string type ); if ($user) { // use $user - returns false if no row found } ``` **Benefits:** - One-liner for single row - Handles null checks automatically - Type specification clear in parameters --- ## Example 3: INSERT (validate_login.php) ### Current Code ```php $query = "INSERT INTO users (email, first_name, last_name, profile_pic, password, is_verified) VALUES (?, ?, ?, ?, ?, ?)"; $stmt = $conn->prepare($query); $is_verified = 1; $stmt->bind_param("sssssi", $email, $first_name, $last_name, $picture, $password, $is_verified); if ($stmt->execute()) { $user_id = $conn->insert_id; // ❌ Bug: insert_id from $conn, not $stmt // use $user_id } $stmt->close(); ``` ### Using DatabaseService ```php $user_id = $db->insert( "INSERT INTO users (email, first_name, last_name, profile_pic, password, is_verified) VALUES (?, ?, ?, ?, ?, ?)", [$email, $first_name, $last_name, $picture, $password, 1], "sssssi" ); if ($user_id) { // $user_id contains the auto-increment ID } else { $error = $db->getLastError(); } ``` **Benefits:** - Returns insert ID directly - Automatic error handling - Cleaner parameter list --- ## Example 4: UPDATE (admin_members.php) ### Current Code ```php $user_id = intval($_POST['user_id']); $stmt = $conn->prepare("UPDATE membership_application SET accept_indemnity = 1 WHERE user_id = ?"); if ($stmt) { $stmt->bind_param("i", $user_id); $stmt->execute(); $stmt->close(); } ``` ### Using DatabaseService ```php $user_id = intval($_POST['user_id']); $affectedRows = $db->update( "UPDATE membership_application SET accept_indemnity = 1 WHERE user_id = ?", [$user_id], "i" ); if ($affectedRows !== false) { // Updated successfully, $affectedRows = number of rows changed } ``` **Benefits:** - Returns affected row count - No manual statement closing - Error available via `$db->getLastError()` --- ## Example 5: COUNT / EXISTS ### Current Pattern (Need 3 lines) ```php $stmt = $conn->prepare("SELECT COUNT(*) as count FROM users WHERE email = ?"); $stmt->bind_param("s", $email); $stmt->execute(); $result = $stmt->get_result(); $row = $result->fetch_assoc(); if ($row['count'] > 0) { /* exists */ } $stmt->close(); ``` ### Using DatabaseService (One line) ```php $exists = $db->exists("users", "email = ?", [$email], "s"); if ($exists) { // User exists } ``` **Benefits:** - Boolean result - Intent is clear - One-liner --- ## Example 6: Multiple Rows with Filtering ### Current Code ```php $status = 'active'; $stmt = $conn->prepare("SELECT * FROM members WHERE status = ? ORDER BY last_name ASC"); $stmt->bind_param("s", $status); $stmt->execute(); $result = $stmt->get_result(); $members = []; while ($row = $result->fetch_assoc()) { $members[] = $row; } $stmt->close(); ``` ### Using DatabaseService ```php $members = $db->select( "SELECT * FROM members WHERE status = ? ORDER BY last_name ASC", ['active'], "s" ); ``` **Benefits:** - Returns array directly - No loop needed - 2 lines vs 8 lines --- ## Example 7: Error Handling ### Current Pattern ```php $stmt = $conn->prepare("SELECT * FROM users WHERE id = ?"); if (!$stmt) { echo "Prepare failed: " . $conn->error; exit(); } $stmt->bind_param("i", $id); if (!$stmt->execute()) { echo "Execute failed: " . $stmt->error; exit(); } ``` ### Using DatabaseService ```php $user = $db->selectOne("SELECT * FROM users WHERE id = ?", [$id], "i"); if ($user === false) { $error = $db->getLastError(); error_log("Database error: " . $error); // handle error } ``` **Benefits:** - Error handling centralized - No null checks for each step - Debug via `$db->getLastQuery()` --- ## Example 8: Transactions ### Current Pattern ```php $conn->begin_transaction(); try { $stmt = $conn->prepare("INSERT INTO orders ..."); $stmt->execute(); $stmt = $conn->prepare("UPDATE inventory ..."); $stmt->execute(); $conn->commit(); } catch (Exception $e) { $conn->rollback(); } ``` ### Using DatabaseService ```php $db->beginTransaction(); $order_id = $db->insert("INSERT INTO orders ...", [...], "..."); if ($order_id === false) { $db->rollback(); exit("Order creation failed"); } $updated = $db->update("UPDATE inventory ...", [...], "..."); if ($updated === false) { $db->rollback(); exit("Inventory update failed"); } $db->commit(); ``` **Benefits:** - Unified transaction API - Built-in error checking - Clean rollback on failure --- ## Type Specification Reference When using DatabaseService methods, specify parameter types: | Type | Meaning | Example | |------|---------|---------| | `"i"` | Integer | `user_id = 5` | | `"d"` | Double/Float | `price = 19.99` | | `"s"` | String | `email = 'test@example.com'` | | `"b"` | Blob | Binary data | Examples: ```php // Single parameter $db->select("SELECT * FROM users WHERE id = ?", [123], "i"); // Multiple parameters $db->select( "SELECT * FROM users WHERE email = ? AND status = ?", ["test@example.com", "active"], "ss" ); // Mixed types $db->select( "SELECT * FROM orders WHERE user_id = ? AND total > ? AND date = ?", [5, 100.50, "2025-01-01"], "ids" // integer, double, string ); ``` --- ## Migration Path ### Phase 1: New Code Start using `$db` for all new features and AJAX endpoints. ### Phase 2: High-Traffic Files Refactor popular files: 1. `validate_login.php` - Login is critical 2. `functions.php` - Helper functions 3. `admin_members.php`, `admin_payments.php` - Admin pages ### Phase 3: Gradual Rollout As each file is refactored, commit and test thoroughly before moving to next. ### Phase 4: Full Migration Eventually all procedural `$conn->prepare()` patterns replaced. --- ## Benefits Summary | Aspect | Before | After | |--------|--------|-------| | Lines per query | 5-8 | 1-3 | | Error handling | Manual checks | Automatic | | Type safety | bind_param() | Parameter array | | Statement closing | Manual | Automatic | | Insert ID handling | `$conn->insert_id` (buggy) | Direct return | | Debugging | Check multiple vars | `getLastError()`, `getLastQuery()` | | Consistency | Varies | Unified API | --- ## Next Steps 1. Start with one file (e.g., `admin_members.php`) 2. Convert simple queries first 3. Test thoroughly 4. Commit and move to next file 5. Keep `$conn` available for complex queries that don't fit the standard patterns The `$db` service makes your code **cleaner, safer, and easier to maintain**.