Initial
This commit is contained in:
parent
45227dd70a
commit
e4c8d7e6c8
1726
.gitignore
vendored
1726
.gitignore
vendored
File diff suppressed because it is too large
Load Diff
37
composer.json
Normal file
37
composer.json
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "goodboyalex/php_db_components_pack",
|
||||||
|
"description": "[RU] Набор компонентов для сайта на PHP для работы с БД / [EN] A set of components for PHP website for working with DB",
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"prefer-stable": true,
|
||||||
|
"keywords": [
|
||||||
|
"components"
|
||||||
|
],
|
||||||
|
"homepage": "https://git.babaev-an.ru/babaev-an/php_db_components_pack",
|
||||||
|
"license": "GPL-3.0-or-later",
|
||||||
|
"type": "library",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Alexander Babaev",
|
||||||
|
"email": "contact_with_us@babaev-an.ru"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": "^8.4",
|
||||||
|
"ext-pdo": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"goodboyalex/php_components_pack": "^v1.2.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^12.2.7"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"goodboyalex\\php_db_components_pack\\": "sources"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"goodboyalex\\php_db_components_pack\\tests\\": "tests"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
823
sources/classes/Database.php
Normal file
823
sources/classes/Database.php
Normal file
@ -0,0 +1,823 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @noinspection SqlNoDataSourceInspection
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\classes;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Exception;
|
||||||
|
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
||||||
|
use goodboyalex\php_db_components_pack\models\DBConfig;
|
||||||
|
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) {
|
||||||
|
$onException($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Деструктор. Закрывает соединение с базой данных
|
||||||
|
*/
|
||||||
|
public function __destruct ()
|
||||||
|
{
|
||||||
|
$this->DataBaseHandle = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выполняем запрос на получение последней строки
|
||||||
|
*
|
||||||
|
* @param string $query Запрос
|
||||||
|
* @param array $params Параметры запроса
|
||||||
|
*
|
||||||
|
* @return false|array Строка в формате массива или false в случае ошибки
|
||||||
|
*
|
||||||
|
* @see Query
|
||||||
|
* @see QueryFirst
|
||||||
|
* @see QueryScalar
|
||||||
|
*/
|
||||||
|
public function QueryLast (string $query, array $params = []): false|array
|
||||||
|
{
|
||||||
|
// Выполняю запрос
|
||||||
|
$result = $this->Query($query, $params);
|
||||||
|
|
||||||
|
// Если в результате запроса получили ошибку или количество строк = 0
|
||||||
|
if ($result === false || count($result) == 0)
|
||||||
|
// - то возвращаем ошибку
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Получаю последний ключ массива
|
||||||
|
$lastKey = array_key_last($result);
|
||||||
|
|
||||||
|
// Возвращаем первую строку
|
||||||
|
return $result[$lastKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Запрос строк из базы данных.
|
||||||
|
*
|
||||||
|
* @param string $query Запрос
|
||||||
|
* @param array $params Параметры запроса
|
||||||
|
*
|
||||||
|
* @return false|array Ассоциированный массив с результатом запроса или false в случае ошибки
|
||||||
|
*/
|
||||||
|
public function Query (string $query, array $params = []): false|array
|
||||||
|
{
|
||||||
|
// По умолчанию, результат пуст
|
||||||
|
$result = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Подготавливаю запрос
|
||||||
|
$STH = $this->DataBaseHandle->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY]);
|
||||||
|
|
||||||
|
// Выполняю запрос
|
||||||
|
$STH->execute($params);
|
||||||
|
|
||||||
|
// Указываю, что данные, которые я хочу получить, должны быть в ассоциативном массиве
|
||||||
|
$STH->setFetchMode(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Получаю все данные
|
||||||
|
$result = $STH->fetchAll();
|
||||||
|
}
|
||||||
|
catch (PDOException $e) {
|
||||||
|
$this->OnException($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вывожу результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выполнение запроса. Обычно используется для операций,
|
||||||
|
* которые не возвращают никаких данных, кроме количества
|
||||||
|
* затронутых ими записей. Например,
|
||||||
|
*
|
||||||
|
* <code>$FcmsDB->Execute('DELETE FROM table WHERE id=1');</code>
|
||||||
|
*
|
||||||
|
* @param string $query Запрос
|
||||||
|
* @param array $params Параметры запроса
|
||||||
|
*
|
||||||
|
* @return int|false Количество затронутых строк или false в случае ошибки
|
||||||
|
*/
|
||||||
|
public function Execute (string $query, array $params = []): int|false
|
||||||
|
{
|
||||||
|
// По умолчанию результат false
|
||||||
|
$result = false;
|
||||||
|
try {
|
||||||
|
// Если параметры не заданы
|
||||||
|
if (count($params) == 0) {
|
||||||
|
// - то выполняю запрос
|
||||||
|
$result = $this->DataBaseHandle->exec($query);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// - в противном случае
|
||||||
|
|
||||||
|
// -- подготавливаю запрос
|
||||||
|
$STH = $this->DataBaseHandle->prepare($query, [PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY]);
|
||||||
|
|
||||||
|
// -- выполняю запрос
|
||||||
|
$opResult = $STH->execute($params);
|
||||||
|
|
||||||
|
// -- и если выполнение успешное,
|
||||||
|
if ($opResult)
|
||||||
|
// --- то в результат пойдёт количество строк
|
||||||
|
$result = $STH->rowCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (PDOException $e) {
|
||||||
|
$this->HandleException($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если в результате false
|
||||||
|
if ($result === false)
|
||||||
|
// - то возвращаю его
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Возвращаю результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function HandleException (Exception $exception): void
|
||||||
|
{
|
||||||
|
$this->OnException($exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получает набор строк в массиве данных, удовлетворяющий выборке
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерирует SQL запрос выборки строк.
|
||||||
|
*
|
||||||
|
* @param string $table Имя таблицы
|
||||||
|
* @param array $columns Колонки, которые нужно включить в запрос
|
||||||
|
* @param array $where Параметры выборки
|
||||||
|
* @param array $params Параметры и их значения
|
||||||
|
*
|
||||||
|
* @return string SQL-запрос
|
||||||
|
*/
|
||||||
|
private function PrepareSQLForRowsQuery (string $table, array $columns = [], array $where = [],
|
||||||
|
array &$params = []): string
|
||||||
|
{
|
||||||
|
// Очищаю параметры
|
||||||
|
$params = [];
|
||||||
|
|
||||||
|
// Строковая интерпретация массива условий
|
||||||
|
$sql_where = $this->PrepareQueryWhere($where, $params);
|
||||||
|
|
||||||
|
// Колонки
|
||||||
|
$sql_columns = count($columns) > 0 ? implode(', ', $this->PrepareColumn($columns)) : "*";
|
||||||
|
|
||||||
|
// Создаю запрос
|
||||||
|
$sql = "SELECT $sql_columns FROM $this->DBSignOpen$table$this->DBSignClose";
|
||||||
|
|
||||||
|
// Если заданы where-параметры
|
||||||
|
if (count($where) > 0) {
|
||||||
|
// - то добавляю их
|
||||||
|
$sql .= " WHERE $sql_where";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаю запрос
|
||||||
|
return $sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Готовит выражение для WHERE-запроса
|
||||||
|
*
|
||||||
|
* @param array $where Массив условий
|
||||||
|
* @param array $params Очищенные параметры
|
||||||
|
*
|
||||||
|
* @return string Строка WHERE-запроса
|
||||||
|
*/
|
||||||
|
private function PrepareQueryWhere (array $where, array &$params): string
|
||||||
|
{
|
||||||
|
// Очищаю параметры
|
||||||
|
$params = [];
|
||||||
|
|
||||||
|
// Задаю результат
|
||||||
|
$result = "";
|
||||||
|
|
||||||
|
// Если массив условий не пуст
|
||||||
|
if (count($where) > 0) {
|
||||||
|
// - то для каждого условия
|
||||||
|
foreach ($where as $key => $value) {
|
||||||
|
// -- получаю ключ 100%-но без ":" в начале
|
||||||
|
$where_key = $key[0] == ":" ? substr($key, 1) : $key;
|
||||||
|
|
||||||
|
// -- добавляю префикс для 2 или более итерации
|
||||||
|
$prefix = $result == "" ? "" : " AND ";
|
||||||
|
|
||||||
|
// -- добавляю данные в $sql_where
|
||||||
|
$result .= $prefix . $this->DBSignOpen . $where_key . $this->DBSignClose . " = :" . $where_key;
|
||||||
|
|
||||||
|
// -- добавляю данные в параметры
|
||||||
|
$params[$where_key] = "$value";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вывожу результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Подготавливает массив столбцов для использования в базе данных
|
||||||
|
*
|
||||||
|
* @param array $columns Массив колонок.
|
||||||
|
*
|
||||||
|
* @return array Массив преобразованных колонок.
|
||||||
|
*/
|
||||||
|
private function PrepareColumn (array $columns): array
|
||||||
|
{
|
||||||
|
return array_map(function ($item)
|
||||||
|
{
|
||||||
|
// Результирующая строка
|
||||||
|
$result = "";
|
||||||
|
|
||||||
|
// Если длинна строки > 0
|
||||||
|
if (strlen($item) > 0) {
|
||||||
|
// - первый символ
|
||||||
|
$firstLetter = substr($item, 0, 1);
|
||||||
|
|
||||||
|
// - последний символ
|
||||||
|
$lastLetter = substr($item, -1);
|
||||||
|
|
||||||
|
// - если первый символ не $this->DBSignOpen
|
||||||
|
if ($firstLetter !== $this->DBSignOpen)
|
||||||
|
// -- то добавляем
|
||||||
|
$result .= $this->DBSignOpen;
|
||||||
|
|
||||||
|
// - добавляем строку
|
||||||
|
$result .= $item;
|
||||||
|
|
||||||
|
// - если последний символ не $this->DBSignClose
|
||||||
|
if ($lastLetter !== $this->DBSignClose)
|
||||||
|
// -- то добавляем
|
||||||
|
$result .= $this->DBSignClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return $result;
|
||||||
|
}, $columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получает первую строку в массиве данных, удовлетворяющую выборке
|
||||||
|
*
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выполняем запрос на получение одной строки (аналог QueryFirst)
|
||||||
|
*
|
||||||
|
* @param string $query Запрос
|
||||||
|
* @param array $params Параметры запроса
|
||||||
|
*
|
||||||
|
* @return false|array Строка в формате массива или false в случае ошибки
|
||||||
|
*
|
||||||
|
* @see Query
|
||||||
|
* @see QueryFirst
|
||||||
|
* @see QueryLast
|
||||||
|
* @see GetRow
|
||||||
|
*/
|
||||||
|
public function QueryScalar (string $query, array $params = []): false|array
|
||||||
|
{
|
||||||
|
return $this->QueryFirst($query, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выполняем запрос на получение первой строки
|
||||||
|
*
|
||||||
|
* @param string $query Запрос
|
||||||
|
* @param array $params Параметры запроса
|
||||||
|
*
|
||||||
|
* @return false|array Строка в формате массива или false в случае ошибки
|
||||||
|
*
|
||||||
|
* @see Query
|
||||||
|
* @see QueryLast
|
||||||
|
* @see QueryScalar
|
||||||
|
*/
|
||||||
|
public function QueryFirst (string $query, array $params = []): false|array
|
||||||
|
{
|
||||||
|
// Выполняю запрос
|
||||||
|
$result = $this->Query($query, $params);
|
||||||
|
|
||||||
|
// Если в результате запроса получили ошибку или количество строк = 0
|
||||||
|
if ($result === false || count($result) == 0)
|
||||||
|
// - то возвращаем ошибку
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Получаю первый ключ массива
|
||||||
|
$firstKey = array_key_first($result);
|
||||||
|
|
||||||
|
// Возвращаем первую строку
|
||||||
|
return $result[$firstKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получает колонку в массиве данных
|
||||||
|
*
|
||||||
|
* @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 $params Параметры
|
||||||
|
*
|
||||||
|
* @return string|false В случае успеха выведет: id созданной записи, -1, если запись создана, но id не получен
|
||||||
|
* (глюк?) и false, если ошибка
|
||||||
|
*/
|
||||||
|
public function Insert (string $table, array $params = []): string|false
|
||||||
|
{
|
||||||
|
// Если массив параметров пуст
|
||||||
|
if (count($params) == 0)
|
||||||
|
// - прерываем с ошибкой
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Подготавливаю массив параметров
|
||||||
|
$params = $this->PrepareParamsArray($params);
|
||||||
|
|
||||||
|
// Получаю ключи параметров
|
||||||
|
$keys = array_keys($params);
|
||||||
|
|
||||||
|
// Создаю результирующий массив имён ключей параметров
|
||||||
|
$keysReal = [];
|
||||||
|
|
||||||
|
// Для каждого ключа параметра
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
// - получаю его имя
|
||||||
|
$keyResult = $key[0] == ":" ? substr($key, 1) : $key;
|
||||||
|
|
||||||
|
// - заключаю в кавычки
|
||||||
|
$keyResult = "$this->DBSignOpen$keyResult$this->DBSignClose";
|
||||||
|
|
||||||
|
// - добавляю в результирующий массив ключей
|
||||||
|
$keysReal[] = $keyResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ключи sql запроса
|
||||||
|
$sql_keys = implode(', ', $keysReal);
|
||||||
|
|
||||||
|
// Значения sql запроса
|
||||||
|
$sql_values = implode(', ', $keys);
|
||||||
|
|
||||||
|
// Создаю запрос
|
||||||
|
$sql = "INSERT INTO $this->DBSignOpen$table$this->DBSignClose ($sql_keys) VALUES ($sql_values);";
|
||||||
|
|
||||||
|
// Выполняю запрос
|
||||||
|
$count = $this->Execute($sql, $params);
|
||||||
|
|
||||||
|
// Если результат - false или добавлена не одна запись
|
||||||
|
if (($count === false) || ($count < 1) || ($count > 1))
|
||||||
|
// - то и общий результат - false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$lastId = -1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Получаю последний id этой записи
|
||||||
|
$lastIdResult = $this->DataBaseHandle->lastInsertId();
|
||||||
|
|
||||||
|
// Если получение неудачное
|
||||||
|
if ($lastIdResult === false)
|
||||||
|
// - то вывожу -1
|
||||||
|
return $lastId;
|
||||||
|
|
||||||
|
// Устанавливаю последний id
|
||||||
|
$lastId = $lastIdResult;
|
||||||
|
}
|
||||||
|
catch (PDOException $e) {
|
||||||
|
$this->HandleException($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вывожу последний id
|
||||||
|
return $lastId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Подготавливает массив параметров
|
||||||
|
*
|
||||||
|
* @param array $params Массив параметров
|
||||||
|
*
|
||||||
|
* @return array|false Подготовленный массив параметров или false в случае ошибки
|
||||||
|
*/
|
||||||
|
private function PrepareParamsArray (array $params = []): array|false
|
||||||
|
{
|
||||||
|
// Если массив параметров пуст
|
||||||
|
if (count($params) == 0)
|
||||||
|
// - прерываем с ошибкой
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Создаём результирующий массив
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Для каждого параметра
|
||||||
|
foreach ($params as $key => $value) {
|
||||||
|
// - если ключ параметра начинается с ":"
|
||||||
|
if ($key[0] == ":")
|
||||||
|
// -- то сразу добавляем его в результирующий массив
|
||||||
|
$result[$key] = $value;
|
||||||
|
else
|
||||||
|
// -- в противном случае, предварительно добавим в имя ключа ":"
|
||||||
|
$result[':' . $key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вывожу результирующий массив
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Заменяет данные в строке базы данных
|
||||||
|
*
|
||||||
|
* @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 ($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;
|
||||||
|
}
|
||||||
|
}
|
45
sources/enums/DBDriver.php
Normal file
45
sources/enums/DBDriver.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\enums;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\traits\EnumExtensionsTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*Перечисление PDO-драйверов.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_db_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
* @see \PDO
|
||||||
|
*/
|
||||||
|
enum DBDriver: int
|
||||||
|
{
|
||||||
|
// Подключаем trait для работы с перечислениями
|
||||||
|
use EnumExtensionsTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MySQL
|
||||||
|
*/
|
||||||
|
case MySQL = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Microsoft SQL
|
||||||
|
*/
|
||||||
|
case MSSQL = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PostgreSQL
|
||||||
|
*/
|
||||||
|
case PostgreSQL = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OracleDB
|
||||||
|
*/
|
||||||
|
case OracleDB = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQLite
|
||||||
|
*/
|
||||||
|
case SQLite = 4;
|
||||||
|
}
|
32
sources/interfaces/IStoredAtSQL.php
Normal file
32
sources/interfaces/IStoredAtSQL.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\interfaces;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Интерфейс поддержки моделей и классов, реализующих хранение свойств в SQL базе данных.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_db_components_pack
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
interface IStoredAtSQL
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Вывод параметров добавления/обновления данных в базу данных.
|
||||||
|
*
|
||||||
|
* @param bool $withId Нужно ли добавлять Id в массив
|
||||||
|
*
|
||||||
|
* @return array Массив параметров
|
||||||
|
*/
|
||||||
|
public function ToSQL (bool $withId = true): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Преобразование данных из базы данных в модель, класс.
|
||||||
|
*
|
||||||
|
* @param array $sqlData Данные из базы данных
|
||||||
|
*
|
||||||
|
* @return self Класс модели с заполненными данными из базы данных
|
||||||
|
*/
|
||||||
|
public function FromSQL (array $sqlData): self;
|
||||||
|
}
|
120
sources/models/DBConfig.php
Normal file
120
sources/models/DBConfig.php
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\models;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\classes\Encryptor;
|
||||||
|
use goodboyalex\php_components_pack\interfaces\ISerializable;
|
||||||
|
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Модель параметров базы данных.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class DBConfig implements ISerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string $Host Хост базы данных.
|
||||||
|
*/
|
||||||
|
public string $Host;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int $Port Порт базы данных.
|
||||||
|
* @between 0...65535
|
||||||
|
*/
|
||||||
|
public int $Port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string $Name Имя базы данных.
|
||||||
|
*/
|
||||||
|
public string $Name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string $UserName Имя пользователя базы данных.
|
||||||
|
*/
|
||||||
|
public string $UserName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string $Password Пароль пользователя базы данных.
|
||||||
|
*/
|
||||||
|
public string $Password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var DBDriver $Driver Тип драйвера базы данных.
|
||||||
|
*/
|
||||||
|
public DBDriver $Driver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string $Chipper Пароль шифрования.
|
||||||
|
*/
|
||||||
|
private string $Chipper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор.
|
||||||
|
*
|
||||||
|
* @param DBDriver $driver Тип драйвера базы данных.
|
||||||
|
* @param string $host Хост базы данных.
|
||||||
|
* @param int $port Порт базы данных.
|
||||||
|
* @param string $name Имя базы данных.
|
||||||
|
* @param string $userName Имя пользователя базы данных.
|
||||||
|
* @param string $password Пароль пользователя базы данных.
|
||||||
|
* @param string $chipper Пароль шифрования.
|
||||||
|
*/
|
||||||
|
public function __construct (DBDriver $driver = DBDriver::MySQL, string $host = "", int $port = 0,
|
||||||
|
string $name = "", string $userName = "", string $password = "", string $chipper = "")
|
||||||
|
{
|
||||||
|
$this->Driver = $driver;
|
||||||
|
$this->Host = $host;
|
||||||
|
$this->Port = $port;
|
||||||
|
$this->Name = $name;
|
||||||
|
$this->UserName = $userName;
|
||||||
|
$this->Password = $password;
|
||||||
|
$this->Chipper = $chipper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function UnSerialize (string $serialized): void
|
||||||
|
{
|
||||||
|
// Десериализую массив
|
||||||
|
$array = json_decode($serialized, true);
|
||||||
|
|
||||||
|
// Заполняю поля
|
||||||
|
if (isset($array["host"]))
|
||||||
|
$this->Host = $array["host"];
|
||||||
|
if (isset($array["port"]))
|
||||||
|
$this->Port = $array["port"];
|
||||||
|
if (isset($array["name"]))
|
||||||
|
$this->Name = $array["name"];
|
||||||
|
if (isset($array["user"]))
|
||||||
|
$this->UserName = $array["user"];
|
||||||
|
if (isset($array["password"]))
|
||||||
|
$this->Password = Encryptor::Decrypt($array["password"], $this->Chipper);
|
||||||
|
if (isset($array["driver"]))
|
||||||
|
$this->Driver = DBDriver::FromInt($array["driver"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function Serialize (): string
|
||||||
|
{
|
||||||
|
// Создаю массив результата
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Заполняю массив
|
||||||
|
$result["host"] = $this->Host;
|
||||||
|
$result["port"] = $this->Port;
|
||||||
|
$result["name"] = $this->Name;
|
||||||
|
$result["user"] = $this->UserName;
|
||||||
|
$result["password"] = Encryptor::Encrypt($this->Password, $this->Chipper);
|
||||||
|
$result["driver"] = $this->Driver->ToInt();
|
||||||
|
|
||||||
|
// Сериализую
|
||||||
|
return json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user