451 lines
18 KiB
PHP
451 lines
18 KiB
PHP
<?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;
|
||
}
|
||
} |