2025-08-02 21:20:32 +03:00

213 lines
8.9 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\traits\Database;
use Exception;
use goodboyalex\php_db_components_pack\classes\ConditionBuilder;
use goodboyalex\php_db_components_pack\classes\DBItemProperty;
use goodboyalex\php_db_components_pack\enums\DBOperation;
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
use PDO;
/**
* Трейт для обновления записей в таблице базы данных.
*
* @author Александр Бабаев
* @package php_db_components_pack
* @version 1.0
* @since 1.0
* @see PDO
*/
trait DatabaseUpdate
{
/**
* Заменяет данные в строке базы данных.
*
* @param string $table Имя таблицы.
* @param IDBItem $item Обновляемый объект.
*
* @return bool Результат выполнения.
*/
public function Update (string $table, IDBItem $item): bool
{
// Получаю свойства объекта
$properties = self::GetProperties($item, DBOperation::Update);
// Получаю первичные ключи объекта
$primaryKeys = $properties->GetRows(fn (DBItemProperty $property): bool => $property->IsPrimaryKey);
// Создаю условие по первичным ключам (оно же и WHERE для обновления)
$where = new ConditionBuilder();
// Для каждого первичного ключа
for ($i = 0; $i < $primaryKeys->Count(); $i++) {
// - если это не первая итерация
if ($i > 0)
// -- то добавляю AND
$where = $where->And();
/**
* Получаю свойство.
*
* @var DBItemProperty $property Свойство.
*/
$property = $primaryKeys[$i];
// - получаю ключ
$whereKey = $property->FieldName;
// - получаю значение ключа, конвертируя его в БД
$whereValue = call_user_func($property->ConvertToDB, $property->Value);
// - добавляю условие в WHERE
$where = $where->WhereEquals($whereKey, $whereValue);
}
// Получаю запись из базы данных
$dbItem = $this->GetRow($table, $where, className: get_class($item));
// Если запись не найдена
if ($dbItem === false)
// - то и общий результат - false
return false;
// Создаю массив параметров для обновления
$propertyToSet = [];
/**
* Для каждого свойства...
*
* @var DBItemProperty $property Свойство.
*/
foreach ($properties as $property) {
// ... если это первичный ключ
if ($property->IsPrimaryKey)
// - то пропускаю его
continue;
// ... если свойство игнорируется
if ($property->IsIgnored)
// - то пропускаю его
continue;
// - получаю значение из базы данных
$inDBValue = $dbItem->{$property->Name};
/**
* Получаю результат сравнения текущего значения и значения из базы данных.
*
* @var bool $compareResult Результат сравнения.
*/
$compareResult = call_user_func($property->Compare, $inDBValue, $property->Value);
// - если значения не изменилось
if ($compareResult)
// -- то и обновлять его не нужно
continue;
// - конвертирую значение в БД
$value = call_user_func($property->ConvertToDB, $property->Value);
// - добавляю его в массив параметров для обновления
$propertyToSet[$property->FieldName] = $value;
}
// Создаю массив set
$set = [];
// Создаю массив параметров set для обновления
$set_params = [];
// Для каждого свойства для обновления
foreach ($propertyToSet as $key => $value) {
// - добавляю его в массив set
$set[] = "$this->DBSignOpen$key$this->DBSignClose=:$key";
// - добавляю его в массив параметров set для обновления
$set_params[":$key"] = $value;
}
// Строковая интерпретация массива set
$sql_set = count($set) > 0 ? '(' . implode(", ", $set) . ')' : "";
/**
* Получаю WHERE-запрос и параметры.
*
* @var string $sql_where WHERE-запрос.
* @var array $where_params Параметры WHERE-запроса.
*/
[$sql_where, $where_params] = $where->Build();
// Объединяю все параметры в один массив
$params = array_merge($set_params, $where_params);
// Создаю запрос
$sql = "UPDATE $this->DBSignOpen$table$this->DBSignClose SET $sql_set";
// Если заданы where-параметры
if ($where->Count() > 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 IDBItem ...$items Массив обновляемых объектов.
*
* @return bool Результат выполнения.
*/
public function UpdateMany (string $table, IDBItem ...$items): bool
{
// Инициализирую транзакцию
$this->InitTransaction();
// Подготавливаю массив последних id
$resultArray = [];
try {
// Для каждого источника
foreach ($items as $item)
// - вставляю строку
$resultArray[] = $this->Update($table, $item);
// Если вставка успешна, то подтверждаю транзакцию
$this->Commit();
}
catch (Exception) {
// - если ошибка, то откатываю транзакцию
$this->RollBack();
// - и вывожу ошибку
return false;
}
// Если есть ошибка
if (array_any($resultArray, fn (bool $value): bool => $value === false))
// - то вывожу ошибку
return false;
// Так как мы дошли до сюда, то это успех! Вывожу результат
return true;
}
}