- Added comprehensive before/after examples - Covers: SELECT, SELECT one, INSERT, UPDATE, DELETE, COUNT, EXISTS - Transaction handling examples - Type specification reference (i, d, s, b) - Migration path and benefits summary - Reduces query code by 50-75% - Guide for gradual implementation throughout codebase
8.0 KiB
8.0 KiB
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:
$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
$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
// 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
$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
$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
$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
$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
$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
$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)
$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)
$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
$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
$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
$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
$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
$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
$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:
// 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:
validate_login.php- Login is criticalfunctions.php- Helper functionsadmin_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
- Start with one file (e.g.,
admin_members.php) - Convert simple queries first
- Test thoroughly
- Commit and move to next file
- Keep
$connavailable for complex queries that don't fit the standard patterns
The $db service makes your code cleaner, safer, and easier to maintain.