2025-07-29 17:50:57 +03:00

451 lines
18 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* @noinspection SqlNoDataSourceInspection
*/
namespace goodboyalex\php_db_components_pack\classes;
use Closure;
use goodboyalex\php_db_components_pack\enums\DBDriver;
use goodboyalex\php_db_components_pack\models\DBConfig;
use goodboyalex\php_db_components_pack\traits\Database\DatabaseInsert;
use goodboyalex\php_db_components_pack\traits\Database\DatabaseQueryExecute;
use goodboyalex\php_db_components_pack\traits\Database\DatabaseSpecial;
use goodboyalex\php_db_components_pack\traits\Database\DatabaseTransactions;
use PDO;
use PDOException;
/**
* Класс для работы с базой данных.
*
* Используется класс PDO для подключения к базе данных.
*
* @author Александр Бабаев
* @package php_components_pack
* @version 1.0
* @since 1.0
* @see PDO
*/
final class Database
{
/**
* @var PDO|null $DataBaseHandle Переменная, хранящая класс PDO.
*/
private ?PDO $DataBaseHandle;
/**
* @var string $DBSignOpen Символ открытия для подстановки в запросы к базе.
*/
private string $DBSignOpen;
/**
* @var string $DBSignСlose Символ закрытия для подстановки в запросы к базе.
*/
private string $DBSignClose;
/**
* @var Closure $OnException Обработчик исключений.
*/
private Closure $OnException;
/**
* @var DBConfig $Config Конфигурация подключения к базе данных.
*/
private DBConfig $Config;
/**
* Конструктор. Подключает базу данных
*
* @param DBConfig $config Конфигурация подключения к базе данных.
* @param callable $onException Обработчик исключений.
*/
public function __construct (DBConfig $config, callable $onException)
{
// Задаю конфигурацию
$this->Config = $config;
// Устанавливаю обработчик исключений
$this->OnException = $onException;
try {
// Загружаю параметры подключения
// - хост
$host = $this->Config->Host;
// - порт
$port = $this->Config->Port;
// - имя базы данных
$dbname = $this->Config->Name;
// - пользователь
$user = $this->Config->UserName;
// - пароль
$password = $this->Config->Password;
// Создаю dsn
$dsn = match ($this->Config->Driver) {
DBDriver::MySQL => "mysql:host=$host;port=$port;dbname=$dbname",
DBDriver::MSSQL => "sqlsrv:Server=$host,$port;Database=$dbname;Encrypt=false;",
DBDriver::PostgreSQL => "pgsql:host=$host;port=$port;dbname=$dbname;",
DBDriver::OracleDB => "oci:dbname=$host:$port/$dbname",
DBDriver::SQLite => "sqlite:$dbname"
};
// Задаю DBSign
// - Open
$this->DBSignOpen = match ($this->Config->Driver) {
DBDriver::MySQL, DBDriver::SQLite => '`',
DBDriver::MSSQL => '[',
DBDriver::PostgreSQL, DBDriver::OracleDB => '"'
};
// - Close
$this->DBSignClose = match ($this->Config->Driver) {
DBDriver::MySQL, DBDriver::SQLite => '`',
DBDriver::MSSQL => ']',
DBDriver::PostgreSQL, DBDriver::OracleDB => '"'
};
// Создаю объект для связи с базой данных
$this->DataBaseHandle = new PDO($dsn, username: $user, password: $password);
// Устанавливаю уровень ошибок
$this->DataBaseHandle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e) {
$this->HandleException($e);
}
}
/**
* Деструктор. Закрывает соединение с базой данных
*/
public function __destruct ()
{
$this->DataBaseHandle = null;
}
/**
* Получает набор строк в массиве данных, удовлетворяющий выборке
*
* @param string $table Имя таблицы
* @param array $columns Колонки, которые нужно включить в запрос
* @param array $where Параметры выборки
*
* @return false|array Строка в формате массива или false в случае ошибки
*
* @see Query
* @see QueryFirst
* @see QueryLast
* @see GetRow
*/
public function GetRows (string $table, array $columns = [], array $where = []): false|array
{
// Задаю массив параметров
$params = [];
// Получаю SQL запрос
$sql = $this->PrepareSQLForRowsQuery($table, $columns, $where, $params);
// Получаю строки на основании запроса
$queryResult = $this->Query($sql, $params);
// Если строки не получены
if ($queryResult === false)
// - то выдаю ошибку
return false;
// Получаю значение строк
return $queryResult;
}
// Транзакции
use DatabaseTransactions;
// Запросы Query и Execute
use DatabaseQueryExecute;
// Вставка данных
use DatabaseInsert;
// Приватные методы
use DatabaseSpecial;
/**
* Получает первую строку в массиве данных, удовлетворяющую выборке
*
* @param string $table Имя таблицы
* @param array $columns Колонки, которые нужно включить в запрос
* @param array $where Параметры выборки
*
* @return false|array Строка в формате массива или false в случае ошибки
*
* @see Query
* @see QueryFirst
* @see QueryLast
* @see QueryScalar
* @see GetRows
*/
public function GetRow (string $table, array $columns = [], array $where = []): false|array
{
// Задаю массив параметров
$params = [];
// Получаю SQL запрос
$sql = $this->PrepareSQLForRowsQuery($table, $columns, $where, $params);
// Получаю строку на основании запроса
return $this->QueryScalar($sql, $params);
}
/**
* Получает колонку в массиве данных
*
* @param string $table Имя таблицы
* @param string $column Имя колонки
* @param array $where Параметры запроса
*
* @return false|array Ассоциированный массив с результатом запроса или false в случае ошибки
*
* @see Query
*/
public function GetCol (string $table, string $column, array $where = []): false|array
{
// Задаю параметры
$params = [];
// Строковая интерпретация массива условий
$sql_where = $this->PrepareQueryWhere($where, $params);
// Создаю запрос
$sql = "SELECT $this->DBSignOpen$column$this->DBSignClose FROM $this->DBSignOpen$table$this->DBSignClose";
// Если заданы where-параметры
if (count($where) > 0) {
// - то добавляю их
$sql .= " WHERE $sql_where";
}
// Получаю столбец на основании запроса
$queryResult = $this->Query($sql, $params);
// Если строка не получена или пуста
if ($queryResult === false)
// - то выдаю ошибку
return false;
// Создаю результат
$result = [];
// Для каждого результата запроса
foreach ($queryResult as $row)
// - передаю его в результат
$result[] = $row[$column];
// Вывожу результат
return $result;
}
/**
* Получение значение единичного поля
*
* @param string $table Имя таблицы
* @param string $column Требуемый столбец
* @param array $where Параметры запроса
*
* @return mixed|null Результат запроса или null в случае ошибки
*/
public function GetValue (string $table, string $column, array $where = []): mixed
{
// Задаю параметры
$params = [];
// Строковая интерпретация массива условий
$sql_where = $this->PrepareQueryWhere($where, $params);
// Создаю запрос
$sql = "SELECT $this->DBSignOpen$column$this->DBSignClose FROM $this->DBSignOpen$table$this->DBSignClose";
// Если заданы where-параметры
if (count($where) > 0) {
// - то добавляю их
$sql .= " WHERE $sql_where";
}
// Получаю строку на основании запроса
$queryResult = $this->QueryScalar($sql, $params);
// Если строка не получена или пуста
if ($queryResult === false || count($queryResult) == 0)
// - то выдаю результат null
return null;
// Получаю значение колонки
return $queryResult[$column];
}
/**
* Заменяет данные в строке базы данных
*
* @param string $table Имя таблицы
* @param array $set Массив данных для замены
* @param array $where Массив условий
*
* @return bool Результат выполнения
*/
public function Update (string $table, array $set, array $where = []): bool
{
// Создаю массив параметров
$params_set = [];
// Строковая интерпретация массива для изменения
$sql_set = "";
// Для каждых данных для изменения
foreach ($set as $key => $value) {
// - получаю ключ 100%-но без ":" в начале
$set_key = $key[0] == ":" ? substr($key, 1) : $key;
// - добавляю префикс для 2 или более итерации
$prefix = $sql_set == "" ? "" : ", ";
// - добавляю данные в sql_set
$sql_set .= "$prefix$this->DBSignOpen$set_key$this->DBSignClose=:$set_key";
// - добавляю данные в параметры
$params_set[":" . $set_key] = $value;
}
// Обработанные параметры
$params_where = [];
// Строковая интерпретация массива условий
$sql_where = $this->PrepareQueryWhere(where: $where, params: $params_where);
// Создаю параметры
$params = array_merge($params_set, $params_where);
// Создаю запрос
$sql = "UPDATE $this->DBSignOpen$table$this->DBSignClose SET $sql_set";
// Если заданы where-параметры
if (count($where) > 0)
// - то добавляю их
$sql .= " WHERE $sql_where";
// Выполняю запрос
$count = $this->Execute($sql, $params);
// Если результат - false
if ($count === false)
// - то и общий результат - false
return false;
// Если изменено 0 строк
if ($count === 0)
// - то и общий результат - false
return false;
// Вывожу результат -- успех
return true;
}
/**
* Проверяет, существует ли запись в таблице.
*
* @param string $table Имя таблицы
* @param array $where Массив условий
*
* @return bool Результат проверки
*/
public function IsExist (string $table, array $where = []): bool
{
// Вывожу результат
return $this->Count($table, $where) > 0;
}
/**
* Подсчитывает количество строк, удовлетворяющих условию.
*
* @param string $table Имя таблицы
* @param array $where Массив условий выборки
*
* @return int Количество строк или -1, в случае ошибки
*/
public function Count (string $table, array $where = []): int
{
// Параметры
$params = [];
// Строковая интерпретация массива условий
$sql_where = $this->PrepareQueryWhere($where, $params);
// Создаю запрос
$sql = "SELECT COUNT(*) FROM $this->DBSignOpen$table$this->DBSignClose";
// Если заданы where-параметры
if (count($where) > 0) {
// - то добавляю их
$sql .= ' WHERE ' . $sql_where;
}
// Выполняю запрос
$countResult = $this->Query($sql, $params);
// Если запрос выполнен с ошибкой
if ($countResult === false)
// - то в результат идёт -1
return -1;
// Получаю секцию
$section = match ($this->Config->Driver) {
DBDriver::MySQL, DBDriver::SQLite => "COUNT(*)",
DBDriver::MSSQL, DBDriver::OracleDB, DBDriver::PostgreSQL => ""
};
// Вывожу количество
return isset($countResult[0][$section]) ? (int)$countResult[0][$section] : -1;
}
/**
* Удаляет строки по условию.
*
* @param string $table Имя таблицы
* @param array $where Массив условий
*
* @return bool Результат выполнения
*/
public function Delete (string $table, array $where = []): bool
{
// Обработанные параметры
$params = [];
// Строковая интерпретация массива условий
$sql_where = $this->PrepareQueryWhere(where: $where, params: $params);
// Создаю запрос
$sql = "DELETE FROM $this->DBSignOpen$table$this->DBSignClose";
// Если заданы where-параметры
if (count($where) > 0) {
// - то добавляю их
$sql .= " WHERE $sql_where";
}
// Выполняю запрос
$count = $this->Execute($sql, $params);
// Если результат - false
if ($count === false)
// - то и общий результат - false
return false;
// Если изменено 0 строк
if ($count === 0)
// - то и общий результат - false
return false;
// Вывожу результат -- успех
return true;
}
}