'SELECT *', 'JOIN' => [], 'ORDERBY' => [], 'LIMIT' => '']; private $_wheres = []; private $_lastQuery = ""; protected function __construct() { $this->init(); } // abstract public function getTable(): string; abstract public function getPKField(): string; abstract public function getTitleField(): string; final public function getConnect(): PDO { if ($this->_db === null) { $driver = $_ENV['DATABASE_DRIVER'] ?? $_SERVER['DATABASE_DRIVER'] ?? 'mysql'; $host = $_ENV['DATABASE_HOST'] ?? $_SERVER['DATABASE_HOST'] ?? 'localhost'; $dbname = $_ENV['DATABASE_DB'] ?? $_SERVER['DATABASE_DB'] ?? 'test'; $charset = $_ENV['DATABASE_CHARSET'] ?? $_SERVER['DATABASE_CHARSET'] ?? 'utf8'; $user = $_ENV['DATABASE_ID'] ?? $_SERVER['DATABASE_ID'] ?? 'root'; $pass = $_ENV['DATABASE_PASSWORD'] ?? $_SERVER['DATABASE_PASSWORD'] ?? ''; $dsn = sprintf("%s:host=%s;dbname=%s;charset=%s", $driver, $host, $dbname, $charset); try { $this->_db = new PDO($dsn, $user, $pass); $this->_db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $this->_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { throw new \Exception("❌ DB 연결 실패: " . $e->getMessage()); } } $this->init(); return $this->_db; } final public function setDebug($debug) { $this->_debug = $debug; } final public function getDebug() { return $this->_debug; } private function init(): void { $debug = $_ENV['DATABASE_QUERY_DEBUG'] ?? $_SERVER['DATABASE_QUERY_DEBUG'] ?? 'false'; if ($debug === "true") { $this->_debug = true; } $this->_reset = true; $this->_querys = ['SELECT' => 'SELECT *', 'JOIN' => [], 'ORDERBY' => [], 'LIMIT' => '']; $this->_wheres = []; $this->_lastQuery = ""; } final public function getLastQuery(): string { return $this->_lastQuery; } //Where절관련 private function getWhereValue(mixed $datas, $delimeter = ","): string { $value = ""; if ($datas === null) { return ""; } if (is_array($datas)) { $temps = []; foreach ($datas as $data) { $data = trim($data); $temps[] = is_string($data) ? "'{$data}'" : $data; } $value = implode($delimeter, $temps); } else { $value = is_string($datas) ? "'{$datas}'" : $datas; } return $value; } private function getWhereColumn(mixed $columns, mixed $datas = null): string { $temps = []; if (is_array($columns)) { //복합배열형태로 들어온 경우 foreach ($columns as $column => $data) { $value = $this->getWhereValue($data); $temps[] = "{$column}={$value}"; } } else { $value = $this->getWhereValue($datas); $temps[] = "{$columns}={$value}"; } // throw new \Exception("DATA:" . $columns . $value === null ? "NULL" : $value); return implode(" ", $temps); } final public function getWhere(): string { return count($this->_wheres) ? "WHERE " . implode(" ", $this->_wheres) : ""; } final public function where(mixed $columns, mixed $values = null, string $delimeter = "AND"): void { $query = $this->getWhereColumn($columns, $values); $this->_wheres[] = count($this->_wheres) ? $delimeter . " " . $query : $query; } final public function orWhere(mixed $columns, mixed $values = null, string $delimeter = "OR"): void { $this->where($columns, $values, $delimeter); } final public function whereLike(string $column, string $value, string $option = "both", string $delimeter = "AND"): void { switch ($option) { case 'before': $value = "%{$value}"; break; case 'after': $value = "{$value}%"; break; default: $value = "%{$value}%"; break; } $this->where("{$column} LIKE '{$value}'", null, $delimeter); } final public function orWhereLike(string $column, string $value, string $option = "both", string $delimeter = "OR"): void { $this->whereLike($column, $value, $option, $delimeter); } final public function whereIn(string $column, array $values, string $delimeter = "AND", $range = "IN") { $query = " {$column} {$range} (" . $this->getWhereValue($values) . ")"; $this->_wheres[] = count($this->_wheres) ? $delimeter . " " . $query : $query; } final public function whereNotIn(string $column, array $values, string $delimeter = "AND", $range = "NOT IN") { $this->whereIn($column, $values, $delimeter, $range); } final public function execute(string $query): bool|PDOStatement { if ($this->_debug) { echo "\n
Query:" . $query . "\n
"; } $this->_lastQuery = $query; $stmt = $this->getConnect()->prepare($query); $stmt->execute(); if ($this->_reset) { $this->init(); } return $stmt; } //CURD문 final protected function create_process(mixed $columns, mixed $values = null): bool|PDOStatement { $query = sprintf("INSERT INTO %s VALUES(%s) %s", $this->getTable(), $this->getWhereColumn($columns, $values), $this->getWhere()); return $this->execute($query); } // final protected function modify_process(mixed $columns, mixed $values = null): bool|PDOStatement { $query = sprintf("UPDATE %s SET %s %s", $this->getTable(), $this->getWhereColumn($columns, $values), $this->getWhere()); return $this->execute($query); } // final protected function delete_process(): bool|PDOStatement { $query = sprintf("DELETE FROM %s %s", $this->getTable(), $this->getWhere()); return $this->execute($query); } // public function select(mixed $columns = "*"): void { $columns = is_array($columns) ? implode(",", $columns) : $columns; $this->_querys["SELECT"] = "SELECT {$columns}"; } //join_type : LEFT, RIGHT, INNER, OUTER final public function join(string $table, mixed $match = null, $join_type = ""): void { $this->_querys['JOIN'][] = " {$join_type} JOIN {$table} ON {$match}"; } final public function orderBy(mixed $columns, string $default_direction = ""): void { $orderBy = ""; if (is_array($columns)) { foreach ($columns as $column => $direction) { $this->orderBy($column, $direction ?? $default_direction); } } else { $this->_querys['ORDERBY'][] = "{$columns} {$default_direction}"; } } final public function limit(int $start, int $offset = 0): void { $offset = $offset > 0 ? ",{$offset}" : ""; $this->_querys["LIMIT"] = " LIMIT {$start} {$offset}"; } //Result private function getResultQuery(string $head, string $tail = ""): string { $join = count($this->_querys['JOIN']) ? implode(",", $this->_querys['JOIN']) : ""; $where = $this->getWhere(); $orderby = count($this->_querys['ORDERBY']) ? "ORDER BY " . implode(",", $this->_querys['ORDERBY']) : ""; return "{$head} FROM {$this->getTable()} {$join} {$where} {$tail} {$orderby} {$this->_querys['LIMIT']}"; } public function getResult($mode = PDO::FETCH_ASSOC): mixed { $stmt = $this->execute($this->getResultQuery($this->_querys['SELECT'])); return $stmt->fetch($mode); } public function getResults($mode = PDO::FETCH_ASSOC): mixed { $stmt = $this->execute($this->getResultQuery($this->_querys['SELECT'])); return $stmt->fetchAll($mode); } final public function countAllResults(string $column = "*", $reset = true): int { $this->_reset = $reset; $stmt = $this->execute($this->getResultQuery("SELECT COUNT({$column})")); $count = $stmt->fetchColumn(0); $this->_reset = true; return $count; } } //Class