diff --git a/DATABASE_SERVICE_EXAMPLES.md b/DATABASE_SERVICE_EXAMPLES.md new file mode 100644 index 00000000..a1884bd9 --- /dev/null +++ b/DATABASE_SERVICE_EXAMPLES.md @@ -0,0 +1,368 @@ +# 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**.