Files
2025-08-20 18:09:37 +03:00

197 lines
8.3 KiB
PHP
Raw Permalink 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\traits\Database;
use Exception;
use goodboyalex\php_components_pack\classes\Tuple;
use goodboyalex\php_db_components_pack\enums\DBDriver;
use goodboyalex\php_db_components_pack\enums\DBOperation;
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
use goodboyalex\php_db_components_pack\models\DBItemProperty;
use PDO;
/**
* Трейт для работы со вставкой строк в базу данных.
*
* @author Александр Бабаев
* @package php_components_pack
* @version 1.0
* @since 1.0
* @see PDO
*/
trait DatabaseInsert
{
/**
* Вставляет строку в базу данных.
*
* @param string $table Имя таблицы.
* @param IDBItem $row Модель или класс, реализующий интерфейс IDBItem, для вставки.
*
* @return mixed В случае успеха выведет: id созданной записи, -1, если запись создана, но id не получен
* (глюк?) и false, если ошибка
*/
public function Insert (string $table, IDBItem $row): mixed
{
// Подготавливаю запрос
[$sql, $params, $primaryKeyValue] = $this->PrepareInsertSQL($table, $row);
// Выполняю запрос
$count = $this->Execute($sql, $params);
// Если результат - false или добавлена не одна запись
if (($count === false) || ($count < 1) || ($count > 1))
// - то и общий результат - false
return false;
// Задаю переменную для последнего id
$lastId = match ($this->Config->Driver) {
DBDriver::MSSQL => $this->Query('SELECT SCOPE_IDENTITY() AS last_inserted_id;')['last_inserted_id'],
DBDriver::MySQL, DBDriver::SQLite => $this->DataBaseHandle->lastInsertId(),
DBDriver::PostgreSQL, DBDriver::OracleDB => $this->DataBaseHandle->lastInsertId('sequence_name')
};
// Если id не получен
if ($lastId === false)
// - то вывожу просто true
$lastId = true;
// Если id не генерировался
if ($lastId === null)
// - то вывожу -1
$lastId = $primaryKeyValue !== "NULL" ? $primaryKeyValue : true;
// Вывожу последний id
return $lastId;
}
/**
* Вставляет несколько строк в базу данных.
*
* @param string $table Имя таблицы.
* @param IDBItem ...$sources Модели или классы, реализующие интерфейс IDBItem, для вставки.
*
* @return false|array Возвращает массив id созданных записей и <code>false</code>, если ошибка.
*/
public function InsertMany (string $table, IDBItem ...$sources): false | array
{
// Инициализирую транзакцию
$this->InitTransaction();
// Подготавливаю массив последних id
$result = [];
try {
// Для каждого источника
foreach ($sources as $source)
// - вставляю строку
$result[] = $this->Insert($table, $source);
// Если вставка успешна, то подтверждаю транзакцию
$this->Commit();
}
catch (Exception) {
// - если ошибка, то откатываю транзакцию
$this->RollBack();
// - и вывожу ошибку
return false;
}
// Вывожу результат
return $result;
}
/**
* Подготавливает запрос для вставки строки в базу данных.
*
* @param string $table Имя таблицы.
* @param IDBItem $row Элемент.
*
* @return Tuple Возвращает [запрос, параметры запроса, значение первичного ключа].
*/
private function PrepareInsertSQL (string $table, IDBItem $row): Tuple
{
// Подготавливаю массив параметров
$params = [];
// Получаю знаки открытия параметра и закрытия его
[$signOpen, $signClose] = DBDriver::GetSigns($this->Config->Driver);
// Получаю массив свойств
$properties = self::GetProperties($row, DBOperation::Insert);
/**
* Для каждого свойства...
*
* @var DBItemProperty $property Свойство.
*/
foreach ($properties as $property) {
// - пропускаю игнорируемые поля
if ($property->IsIgnored)
continue;
// - получаю значение имени поля
$fieldName = $property->Column->Name;
// - преобразую тип
$value = call_user_func($property->ConvertToDB, $property->Value);
// - добавляю в массив
$params[$fieldName] = $value;
}
// Получаю ключи параметров
$keys = array_keys($params);
// Создаю результирующий массив имён ключей параметров
$keys_params = [];
// Создаю результирующий массив значений параметров
$keys_values = [];
// Для каждого ключа параметра
foreach ($keys as $key) {
// - получаю его имя
$keyReal = $key[0] == ":" ? substr($key, 1) : $key;
// - добавляю в результирующий массив ключей
$keys_params[] = "$signOpen$keyReal$signClose";
// - добавляю в результирующий массив значений
$keys_values[] = ":$keyReal";
}
// Ключи sql запроса
$sql_keys = implode(', ', $keys_params);
// Значения sql запроса
$sql_values = implode(', ', $keys_values);
// Подготавливаю имя таблицы
$table = $this->PrepareTableName($table);
// Создаю запрос
$sql = "INSERT INTO $table ($sql_keys) VALUES ($sql_values);";
/**
* Получаю первичный ключ таблицы.
*
* @var false|DBItemProperty $key Первичный ключ таблицы.
*/
$key = $properties->GetRow(
selectCondition: fn (DBItemProperty $property): bool => $property->Column->IsPrimaryKey
);
// Передаю первичный ключ в переменную
$pKey = $key === false ? 'NULL' : $key->Value ?? "NULL";
// Возвращаю результат
return new Tuple($sql, $params, $pKey);
}
}