213 lines
8.9 KiB
PHP
213 lines
8.9 KiB
PHP
<?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\enums\DBOperation;
|
||
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
||
use goodboyalex\php_db_components_pack\models\DBItemProperty;
|
||
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->Column->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->Column->Name;
|
||
|
||
// - получаю значение ключа, конвертируя его в БД
|
||
$whereValue = call_user_func($property->ConvertToDB, $property->Value);
|
||
|
||
// - добавляю условие в WHERE
|
||
$where = $where->WhereEquals($whereKey, $whereValue);
|
||
}
|
||
|
||
// Получаю запись из базы данных
|
||
$dbItem = $this->GetRow($table, where: $where, className: get_class($item));
|
||
|
||
// Если запись не найдена
|
||
if ($dbItem === false)
|
||
// - то и общий результат - false
|
||
return false;
|
||
|
||
// Создаю массив параметров для обновления
|
||
$propertyToSet = [];
|
||
|
||
/**
|
||
* Для каждого свойства...
|
||
*
|
||
* @var DBItemProperty $property Свойство.
|
||
*/
|
||
foreach ($properties as $property) {
|
||
// ... если это первичный ключ
|
||
if ($property->Column->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->Column->Name] = $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;
|
||
}
|
||
} |