- Created DatabaseService.php with full OOP database abstraction layer - Methods: select(), selectOne(), insert(), update(), delete(), execute(), count(), exists() - Transaction support: beginTransaction(), commit(), rollback() - Error handling: getLastError(), getLastQuery() for debugging - Type-safe parameter binding with prepared statements - Updated connection.php to initialize $db service - Available globally as $db variable after connection.php include - Foundation for migrating from procedural $conn queries
321 lines
9.4 KiB
PHP
321 lines
9.4 KiB
PHP
<?php
|
|
/**
|
|
* DatabaseService Class
|
|
*
|
|
* Provides a centralized database abstraction layer for all database operations.
|
|
* Enforces prepared statements, proper error handling, and type safety.
|
|
*
|
|
* @package 4WDCSA
|
|
* @version 1.0
|
|
*/
|
|
|
|
class DatabaseService {
|
|
private $conn;
|
|
private $lastError = null;
|
|
private $lastQuery = null;
|
|
|
|
/**
|
|
* Constructor - Initialize database connection
|
|
*
|
|
* @param mysqli $connection The MySQLi connection object
|
|
*/
|
|
public function __construct($connection) {
|
|
if (!$connection) {
|
|
throw new Exception("Database connection failed");
|
|
}
|
|
$this->conn = $connection;
|
|
}
|
|
|
|
/**
|
|
* Get the last error message
|
|
*
|
|
* @return string|null The last error or null if no error
|
|
*/
|
|
public function getLastError() {
|
|
return $this->lastError;
|
|
}
|
|
|
|
/**
|
|
* Get the last executed query
|
|
*
|
|
* @return string|null The last query or null
|
|
*/
|
|
public function getLastQuery() {
|
|
return $this->lastQuery;
|
|
}
|
|
|
|
/**
|
|
* Execute a SELECT query with parameter binding
|
|
*
|
|
* @param string $query SQL query with ? placeholders
|
|
* @param array $params Parameters to bind
|
|
* @param string $types Type specification string (e.g., "isi" for int, string, int)
|
|
* @return array|false Array of results or false on error
|
|
*/
|
|
public function select($query, $params = [], $types = "") {
|
|
try {
|
|
$this->lastQuery = $query;
|
|
$stmt = $this->conn->prepare($query);
|
|
|
|
if (!$stmt) {
|
|
$this->lastError = "Prepare failed: " . $this->conn->error;
|
|
return false;
|
|
}
|
|
|
|
if (!empty($params) && !empty($types)) {
|
|
if (!$stmt->bind_param($types, ...$params)) {
|
|
$this->lastError = "Bind failed: " . $stmt->error;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!$stmt->execute()) {
|
|
$this->lastError = "Execute failed: " . $stmt->error;
|
|
return false;
|
|
}
|
|
|
|
$result = $stmt->get_result();
|
|
$data = [];
|
|
|
|
while ($row = $result->fetch_assoc()) {
|
|
$data[] = $row;
|
|
}
|
|
|
|
$stmt->close();
|
|
return $data;
|
|
|
|
} catch (Exception $e) {
|
|
$this->lastError = $e->getMessage();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute a SELECT query returning a single row
|
|
*
|
|
* @param string $query SQL query with ? placeholders
|
|
* @param array $params Parameters to bind
|
|
* @param string $types Type specification string
|
|
* @return array|false Single row as associative array or false
|
|
*/
|
|
public function selectOne($query, $params = [], $types = "") {
|
|
$results = $this->select($query, $params, $types);
|
|
return ($results && count($results) > 0) ? $results[0] : false;
|
|
}
|
|
|
|
/**
|
|
* Execute an INSERT query
|
|
*
|
|
* @param string $query SQL query with ? placeholders
|
|
* @param array $params Parameters to bind
|
|
* @param string $types Type specification string
|
|
* @return int|false Last insert ID or false on error
|
|
*/
|
|
public function insert($query, $params = [], $types = "") {
|
|
try {
|
|
$this->lastQuery = $query;
|
|
$stmt = $this->conn->prepare($query);
|
|
|
|
if (!$stmt) {
|
|
$this->lastError = "Prepare failed: " . $this->conn->error;
|
|
return false;
|
|
}
|
|
|
|
if (!empty($params) && !empty($types)) {
|
|
if (!$stmt->bind_param($types, ...$params)) {
|
|
$this->lastError = "Bind failed: " . $stmt->error;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!$stmt->execute()) {
|
|
$this->lastError = "Execute failed: " . $stmt->error;
|
|
return false;
|
|
}
|
|
|
|
$insertId = $stmt->insert_id;
|
|
$stmt->close();
|
|
return $insertId;
|
|
|
|
} catch (Exception $e) {
|
|
$this->lastError = $e->getMessage();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute an UPDATE query
|
|
*
|
|
* @param string $query SQL query with ? placeholders
|
|
* @param array $params Parameters to bind
|
|
* @param string $types Type specification string
|
|
* @return int|false Number of affected rows or false on error
|
|
*/
|
|
public function update($query, $params = [], $types = "") {
|
|
try {
|
|
$this->lastQuery = $query;
|
|
$stmt = $this->conn->prepare($query);
|
|
|
|
if (!$stmt) {
|
|
$this->lastError = "Prepare failed: " . $this->conn->error;
|
|
return false;
|
|
}
|
|
|
|
if (!empty($params) && !empty($types)) {
|
|
if (!$stmt->bind_param($types, ...$params)) {
|
|
$this->lastError = "Bind failed: " . $stmt->error;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!$stmt->execute()) {
|
|
$this->lastError = "Execute failed: " . $stmt->error;
|
|
return false;
|
|
}
|
|
|
|
$affectedRows = $stmt->affected_rows;
|
|
$stmt->close();
|
|
return $affectedRows;
|
|
|
|
} catch (Exception $e) {
|
|
$this->lastError = $e->getMessage();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute a DELETE query
|
|
*
|
|
* @param string $query SQL query with ? placeholders
|
|
* @param array $params Parameters to bind
|
|
* @param string $types Type specification string
|
|
* @return int|false Number of affected rows or false on error
|
|
*/
|
|
public function delete($query, $params = [], $types = "") {
|
|
return $this->update($query, $params, $types);
|
|
}
|
|
|
|
/**
|
|
* Execute an arbitrary query (for complex queries)
|
|
*
|
|
* @param string $query SQL query with ? placeholders
|
|
* @param array $params Parameters to bind
|
|
* @param string $types Type specification string
|
|
* @return mixed Query result or false on error
|
|
*/
|
|
public function execute($query, $params = [], $types = "") {
|
|
try {
|
|
$this->lastQuery = $query;
|
|
$stmt = $this->conn->prepare($query);
|
|
|
|
if (!$stmt) {
|
|
$this->lastError = "Prepare failed: " . $this->conn->error;
|
|
return false;
|
|
}
|
|
|
|
if (!empty($params) && !empty($types)) {
|
|
if (!$stmt->bind_param($types, ...$params)) {
|
|
$this->lastError = "Bind failed: " . $stmt->error;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!$stmt->execute()) {
|
|
$this->lastError = "Execute failed: " . $stmt->error;
|
|
return false;
|
|
}
|
|
|
|
$stmt->close();
|
|
return true;
|
|
|
|
} catch (Exception $e) {
|
|
$this->lastError = $e->getMessage();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Count rows matching a condition
|
|
*
|
|
* @param string $table Table name
|
|
* @param string $where WHERE clause (without WHERE keyword)
|
|
* @param array $params Parameters to bind
|
|
* @param string $types Type specification string
|
|
* @return int|false Row count or false on error
|
|
*/
|
|
public function count($table, $where = "1=1", $params = [], $types = "") {
|
|
$query = "SELECT COUNT(*) as count FROM {$table} WHERE {$where}";
|
|
$result = $this->selectOne($query, $params, $types);
|
|
return ($result) ? (int)$result['count'] : false;
|
|
}
|
|
|
|
/**
|
|
* Check if a record exists
|
|
*
|
|
* @param string $table Table name
|
|
* @param string $where WHERE clause (without WHERE keyword)
|
|
* @param array $params Parameters to bind
|
|
* @param string $types Type specification string
|
|
* @return bool True if record exists, false otherwise
|
|
*/
|
|
public function exists($table, $where, $params = [], $types = "") {
|
|
$count = $this->count($table, $where, $params, $types);
|
|
return ($count !== false && $count > 0);
|
|
}
|
|
|
|
/**
|
|
* Get the MySQLi connection object for advanced operations
|
|
*
|
|
* @return mysqli The MySQLi connection
|
|
*/
|
|
public function getConnection() {
|
|
return $this->conn;
|
|
}
|
|
|
|
/**
|
|
* Start a transaction
|
|
*
|
|
* @return bool Success status
|
|
*/
|
|
public function beginTransaction() {
|
|
try {
|
|
$this->conn->begin_transaction();
|
|
return true;
|
|
} catch (Exception $e) {
|
|
$this->lastError = $e->getMessage();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Commit a transaction
|
|
*
|
|
* @return bool Success status
|
|
*/
|
|
public function commit() {
|
|
try {
|
|
$this->conn->commit();
|
|
return true;
|
|
} catch (Exception $e) {
|
|
$this->lastError = $e->getMessage();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Rollback a transaction
|
|
*
|
|
* @return bool Success status
|
|
*/
|
|
public function rollback() {
|
|
try {
|
|
$this->conn->rollback();
|
|
return true;
|
|
} catch (Exception $e) {
|
|
$this->lastError = $e->getMessage();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
?>
|