From 0143f5dd1218448d588e5735db1bac10468cb803 Mon Sep 17 00:00:00 2001 From: twotalesanimation <80506065+twotalesanimation@users.noreply.github.com> Date: Wed, 3 Dec 2025 19:59:32 +0200 Subject: [PATCH] Add: DatabaseService class for abstracted database operations - 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 --- classes/DatabaseService.php | 320 ++++++++++++++++++++++++++++++++++++ connection.php | 4 + 2 files changed, 324 insertions(+) create mode 100644 classes/DatabaseService.php diff --git a/classes/DatabaseService.php b/classes/DatabaseService.php new file mode 100644 index 00000000..86e131d2 --- /dev/null +++ b/classes/DatabaseService.php @@ -0,0 +1,320 @@ +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; + } + } +} +?> diff --git a/connection.php b/connection.php index 8b1b1aaa..942a1338 100644 --- a/connection.php +++ b/connection.php @@ -13,3 +13,7 @@ if(!$conn = mysqli_connect($dbhost, $dbuser, $dbpass, $dbname)){ } date_default_timezone_set('Africa/Johannesburg'); + +// Initialize DatabaseService for modern queries +require_once(__DIR__ . '/classes/DatabaseService.php'); +$db = new DatabaseService($conn);