20250729
This commit is contained in:
parent
e4c8d7e6c8
commit
8436569ce5
70
.idea/codeStyles/Project.xml
generated
Normal file
70
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<PHPCodeStyleSettings>
|
||||||
|
<option name="INDENT_CODE_IN_PHP_TAGS" value="true" />
|
||||||
|
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
|
||||||
|
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
|
||||||
|
<option name="PHPDOC_WRAP_LONG_LINES" value="true" />
|
||||||
|
<option name="ANONYMOUS_BRACE_STYLE" value="5" />
|
||||||
|
<option name="LINK_WEIGHT" value="11" />
|
||||||
|
<option name="AUTHOR_WEIGHT" value="3" />
|
||||||
|
<option name="USES_WEIGHT" value="9" />
|
||||||
|
<option name="VERSION_WEIGHT" value="5" />
|
||||||
|
<option name="COPYRIGHT_WEIGHT" value="7" />
|
||||||
|
<option name="PACKAGE_WEIGHT" value="4" />
|
||||||
|
<option name="SEE_WEIGHT" value="8" />
|
||||||
|
<option name="SINCE_WEIGHT" value="6" />
|
||||||
|
<option name="TODO_WEIGHT" value="10" />
|
||||||
|
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
|
||||||
|
<option name="LOWER_CASE_NULL_CONST" value="true" />
|
||||||
|
<option name="ELSE_IF_STYLE" value="SEPARATE" />
|
||||||
|
<option name="SPACE_BEFORE_SHORT_CLOSURE_LEFT_PARENTHESIS" value="true" />
|
||||||
|
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
|
||||||
|
<option name="SPACE_AROUND_ASSIGNMENT_IN_DECLARE" value="true" />
|
||||||
|
<option name="FORCE_EMPTY_CLASSES_IN_ONE_LINE" value="true" />
|
||||||
|
<option name="MULTILINE_CLOSURE_LAMBDA_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="ATTRIBUTES_WRAP" value="1" />
|
||||||
|
<option name="PARAMETERS_ATTRIBUTES_WRAP" value="1" />
|
||||||
|
</PHPCodeStyleSettings>
|
||||||
|
<codeStyleSettings language="PHP">
|
||||||
|
<option name="LAMBDA_BRACE_STYLE" value="5" />
|
||||||
|
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="WHILE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="CATCH_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="FINALLY_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="SPECIAL_ELSE_IF_TREATMENT" value="true" />
|
||||||
|
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||||
|
<option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_METHOD_PARENTHESES" value="true" />
|
||||||
|
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||||
|
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
||||||
|
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
|
||||||
|
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
|
||||||
|
<option name="BINARY_OPERATION_WRAP" value="1" />
|
||||||
|
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
|
||||||
|
<option name="TERNARY_OPERATION_WRAP" value="1" />
|
||||||
|
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
|
||||||
|
<option name="FOR_STATEMENT_WRAP" value="1" />
|
||||||
|
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
||||||
|
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
|
||||||
|
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
|
||||||
|
<option name="ASSIGNMENT_WRAP" value="1" />
|
||||||
|
<option name="WRAP_ON_TYPING" value="1" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
<arrangement>
|
||||||
|
<groups>
|
||||||
|
<group>
|
||||||
|
<type>GETTERS_AND_SETTERS</type>
|
||||||
|
<order>KEEP</order>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<type>OVERRIDDEN_METHODS</type>
|
||||||
|
<order>KEEP</order>
|
||||||
|
</group>
|
||||||
|
</groups>
|
||||||
|
</arrangement>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
File diff suppressed because it is too large
Load Diff
32
sources/interfaces/IDBItem.php
Normal file
32
sources/interfaces/IDBItem.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 IDBItem
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Вывод параметров добавления/обновления данных в базу данных.
|
||||||
|
*
|
||||||
|
* @param bool $withId Нужно ли добавлять Id в массив
|
||||||
|
*
|
||||||
|
* @return array Массив параметров
|
||||||
|
*/
|
||||||
|
public function ToSQL (bool $withId = true): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Преобразование данных из базы данных в модель, класс.
|
||||||
|
*
|
||||||
|
* @param array $sqlData Данные из базы данных
|
||||||
|
*
|
||||||
|
* @return self Класс модели с заполненными данными из базы данных
|
||||||
|
*/
|
||||||
|
public function FromSQL (array $sqlData): self;
|
||||||
|
}
|
@ -1,32 +0,0 @@
|
|||||||
<?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;
|
|
||||||
}
|
|
153
sources/traits/Database/DatabaseInsert.php
Normal file
153
sources/traits/Database/DatabaseInsert.php
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @noinspection SqlNoDataSourceInspection
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\traits\Database;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use goodboyalex\php_components_pack\classes\Tuple;
|
||||||
|
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
||||||
|
use PDO;
|
||||||
|
use PDOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Трейт для работы со вставкой строк в базу данных.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
* @see PDO
|
||||||
|
*/
|
||||||
|
trait DatabaseInsert
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Вставляет строку в базу данных.
|
||||||
|
*
|
||||||
|
* @param string $table Имя таблицы.
|
||||||
|
* @param IDBItem $row Модель или класс, реализующий интерфейс IDBItem, для вставки.
|
||||||
|
* @param array $options Массив дополнительных параметров. Может содержать следующие ключи:
|
||||||
|
*
|
||||||
|
* - <code>ignore: array</code> - игнорировать перечисленные поля. Когда массив пуст, то ничего
|
||||||
|
* игнорироваться не будет. По умолчанию - пустой массив.
|
||||||
|
* - <code>allow: array</code> - включать только перечисленные поля. Когда массив пуст, то все поля будут
|
||||||
|
* включены. По умолчанию - пустой массив.
|
||||||
|
*
|
||||||
|
* @return string|false В случае успеха выведет: id созданной записи, -1, если запись создана, но id не получен
|
||||||
|
* (глюк?) и false, если ошибка
|
||||||
|
*/
|
||||||
|
public function Insert (string $table, IDBItem $row, array $options = []): string|false
|
||||||
|
{
|
||||||
|
// Подготавливаю запрос
|
||||||
|
[$sql, $params] = $this->PrepareInsertSQL($table, $row, $options);
|
||||||
|
|
||||||
|
// Выполняю запрос
|
||||||
|
$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 string $table Имя таблицы.
|
||||||
|
* @param array $options Параметры.
|
||||||
|
* @param IDBItem ...$sources Модели или классы, реализующие интерфейс IDBItem, для вставки.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function InsertMany (string $table, array $options, IDBItem ...$sources): void
|
||||||
|
{
|
||||||
|
// Инициализирую транзакцию
|
||||||
|
$this->InitTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Для каждого источника
|
||||||
|
foreach ($sources as $source)
|
||||||
|
// - вставляю строку
|
||||||
|
$this->Insert($table, $source, $options);
|
||||||
|
|
||||||
|
// Если вставка успешна, то подтверждаю транзакцию
|
||||||
|
$this->Commit();
|
||||||
|
}
|
||||||
|
catch (Exception $exception) {
|
||||||
|
// - если ошибка, то откатываю транзакцию
|
||||||
|
$this->RollBack();
|
||||||
|
|
||||||
|
// - и вывожу ошибку
|
||||||
|
$this->HandleException($exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Подготавливает запрос для вставки строки в базу данных.
|
||||||
|
*
|
||||||
|
* @param string $table Имя таблицы.
|
||||||
|
* @param IDBItem $row Элемент.
|
||||||
|
* @param array $options Параметры.
|
||||||
|
*
|
||||||
|
* @return Tuple Возвращает [запрос, параметры запроса].
|
||||||
|
*/
|
||||||
|
private function PrepareInsertSQL (string $table, IDBItem $row, array $options = []): Tuple
|
||||||
|
{
|
||||||
|
// Подготавливаю массив параметров
|
||||||
|
$params = $this->PrepareParamsArray(source: $row, options: $options);
|
||||||
|
|
||||||
|
// Получаю ключи параметров
|
||||||
|
$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);";
|
||||||
|
|
||||||
|
// Возвращаю результат
|
||||||
|
return new Tuple($sql, $params);
|
||||||
|
}
|
||||||
|
}
|
182
sources/traits/Database/DatabaseQueryExecute.php
Normal file
182
sources/traits/Database/DatabaseQueryExecute.php
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @noinspection SqlNoDataSourceInspection
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\traits\Database;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
use PDOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Трейт для работы с запросами к базе данных типа Query и Execute.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
* @see PDO
|
||||||
|
*/
|
||||||
|
trait DatabaseQueryExecute
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Запрос строк из базы данных.
|
||||||
|
*
|
||||||
|
* @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->HandleException($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вывожу результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выполняем запрос на получение одной строки (аналог 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 $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];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выполнение запроса. Обычно используется для операций,
|
||||||
|
* которые не возвращают никаких данных, кроме количества
|
||||||
|
* затронутых ими записей. Например,
|
||||||
|
*
|
||||||
|
* <code>$db->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;
|
||||||
|
}
|
||||||
|
}
|
248
sources/traits/Database/DatabaseSpecial.php
Normal file
248
sources/traits/Database/DatabaseSpecial.php
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @noinspection SqlNoDataSourceInspection
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\traits\Database;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use goodboyalex\php_components_pack\exceptions\TypeException;
|
||||||
|
use goodboyalex\php_components_pack\extensions\TypeExtension;
|
||||||
|
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Трейт для функций поддержки для работы с базой данных.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
* @see PDO
|
||||||
|
*/
|
||||||
|
trait DatabaseSpecial
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Добавляет параметр в массив.
|
||||||
|
*
|
||||||
|
* @param array $array Массив.
|
||||||
|
* @param string $key Имя параметра.
|
||||||
|
* @param mixed $value Значение параметра.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function AddArrayItem (array &$array, string $key, mixed $value): void
|
||||||
|
{
|
||||||
|
// Если ключ параметра начинается с ":"
|
||||||
|
if ($key[0] == ":")
|
||||||
|
// - то сразу добавляем его в результирующий массив
|
||||||
|
$array[$key] = $value;
|
||||||
|
else
|
||||||
|
// - в противном случае, предварительно добавим в имя ключа ":"
|
||||||
|
$array[':' . $key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обрабатывает исключение.
|
||||||
|
*
|
||||||
|
* @param Exception $exception Исключение.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function HandleException (Exception $exception): void
|
||||||
|
{
|
||||||
|
// Выбираю обработчик исключений
|
||||||
|
$onException = $this->OnException ?? fn (Exception $e) => die($e->getMessage());
|
||||||
|
|
||||||
|
// Выполняю обработчик исключений
|
||||||
|
$onException($exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Подготавливает массив параметров
|
||||||
|
*
|
||||||
|
* @param IDBItem $source Объект со свойствами.
|
||||||
|
* @param bool $withId Добавлять ли id в массив.
|
||||||
|
* @param array $options Опции.
|
||||||
|
*
|
||||||
|
* @return array|false Подготовленный массив параметров или false в случае ошибки
|
||||||
|
*/
|
||||||
|
private function PrepareParamsArray (IDBItem $source, bool $withId = true, array $options = []): array|false
|
||||||
|
{
|
||||||
|
// Создаём результирующий массив
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Если есть игнорируемые или разрешенные свойства
|
||||||
|
if (!(count($options['ignore']) == 0 && count($options['allow']) == 0))
|
||||||
|
// -- то для каждого игнорируемого свойства
|
||||||
|
foreach ($options['ignored'] as $ignoredProperty)
|
||||||
|
// --- и если оно есть в массиве разрешенных
|
||||||
|
if (in_array($ignoredProperty, $options['allowed']))
|
||||||
|
// ---- то исключаю его из массива разрешенных
|
||||||
|
unset($options['allowed'][array_search($ignoredProperty, $options['allowed'])]);
|
||||||
|
|
||||||
|
// Получаю массив свойств
|
||||||
|
$properties = $source->ToSQL($withId);
|
||||||
|
|
||||||
|
// Для каждого элемента массива
|
||||||
|
foreach ($properties as $name => $value) {
|
||||||
|
// - если свойство игнорируется
|
||||||
|
if (in_array($name, $options['ignored']))
|
||||||
|
// -- пропускаю
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - если свойство не разрешено
|
||||||
|
if (count($options['allowed']) > 0 && !in_array($name, $options['allowed']))
|
||||||
|
// -- пропускаю
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - если свойство является объектом
|
||||||
|
if (is_object($source->$name)) {
|
||||||
|
try {
|
||||||
|
// -- пытаюсь преобразовать его в массив
|
||||||
|
self::AddArrayItem($result, $name, json_encode(TypeExtension::ToArray($source->$name),
|
||||||
|
JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||||
|
}
|
||||||
|
catch (TypeException) {
|
||||||
|
// -- если не получилось, то сериализую его
|
||||||
|
self::AddArrayItem($result, $name,
|
||||||
|
json_encode($source->$name, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- пропускаю
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - если свойство является массивом
|
||||||
|
if (is_array($source->$name)) {
|
||||||
|
// -- сериализую его
|
||||||
|
self::AddArrayItem($result, $name, json_encode($source->$name, JSON_UNESCAPED_UNICODE |
|
||||||
|
JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
|
// -- пропускаю
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - иначе просто добавляю свойство в массив
|
||||||
|
self::AddArrayItem($result, $name, $source->$name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вывожу результирующий массив
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерирует 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;
|
||||||
|
}
|
||||||
|
}
|
98
sources/traits/Database/DatabaseTransactions.php
Normal file
98
sources/traits/Database/DatabaseTransactions.php
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @noinspection SqlNoDataSourceInspection
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\traits\Database;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
use PDOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Трейт для работы с транзакциями базы данных.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
* @see PDO
|
||||||
|
*/
|
||||||
|
trait DatabaseTransactions
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Начинает транзакцию.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws PDOException Если транзакция уже начата или не удалось начать.
|
||||||
|
*/
|
||||||
|
public function InitTransaction (): void
|
||||||
|
{
|
||||||
|
// Проверка, не находится ли текущая транзакция в процессе.
|
||||||
|
if ($this->InTransaction())
|
||||||
|
// - если находится, то выбрасываем исключение.
|
||||||
|
throw new PDOException("Транзакция уже начата! / Transaction already started!");
|
||||||
|
|
||||||
|
// Начинаем транзакцию
|
||||||
|
$isSuccess = $this->DataBaseHandle->beginTransaction();
|
||||||
|
|
||||||
|
// Если транзакция не началась
|
||||||
|
if (!$isSuccess)
|
||||||
|
// - то выбрасываем исключение.
|
||||||
|
throw new PDOException("Ошибка при начале транзакции! / Transaction start error!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, находится ли текущая транзакция в процессе.
|
||||||
|
*
|
||||||
|
* @return bool Результат проверки: <code>true</code> - в процессе, <code>false</code> - нет.
|
||||||
|
*/
|
||||||
|
public function InTransaction (): bool
|
||||||
|
{
|
||||||
|
return $this->DataBaseHandle->inTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Отправляет транзакцию в базу данных.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws PDOException Если транзакция не начата или не отправлена.
|
||||||
|
*/
|
||||||
|
public function Commit (): void
|
||||||
|
{
|
||||||
|
// Проверка, не находится ли текущая транзакция в процессе
|
||||||
|
if (!$this->InTransaction())
|
||||||
|
// - если нет, то выбрасываем исключение.
|
||||||
|
throw new PDOException("Транзакция не начата! / Transaction not started!");
|
||||||
|
|
||||||
|
// Отправляем транзакцию в базу данных
|
||||||
|
$isSuccess = $this->DataBaseHandle->commit();
|
||||||
|
|
||||||
|
// Если транзакция не отправлена
|
||||||
|
if (!$isSuccess)
|
||||||
|
// - то выбрасываем исключение.
|
||||||
|
throw new PDOException("Ошибка при отправке транзакции в базу данных! / Transaction send error!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Откатывает транзакцию.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws PDOException Если транзакция не начата или не откатана.
|
||||||
|
*/
|
||||||
|
public function RollBack (): void
|
||||||
|
{
|
||||||
|
// Проверка, не находится ли текущая транзакция в процессе
|
||||||
|
if (!$this->InTransaction())
|
||||||
|
// - если нет, то выбрасываем исключение.
|
||||||
|
throw new PDOException("Транзакция не начата! / Transaction not started!");
|
||||||
|
|
||||||
|
// Откатываем транзакцию
|
||||||
|
$isSuccess = $this->DataBaseHandle->rollBack();
|
||||||
|
|
||||||
|
// Если транзакция не откатана
|
||||||
|
if (!$isSuccess)
|
||||||
|
// - то выбрасываем исключение.
|
||||||
|
throw new PDOException("Ошибка при откате транзакции! / Transaction rollback error!");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user