20250802-1
This commit is contained in:
parent
4ec8ccc089
commit
a80c4e6f65
23
.gitignore
vendored
23
.gitignore
vendored
@ -398,8 +398,6 @@ node_modules/
|
|||||||
*.dsp
|
*.dsp
|
||||||
|
|
||||||
# Visual Studio 6 technical files
|
# Visual Studio 6 technical files
|
||||||
*.ncb
|
|
||||||
*.aps
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
# Visual Studio LightSwitch build output
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
@ -473,15 +471,9 @@ MigrationBackup/
|
|||||||
FodyWeavers.xsd
|
FodyWeavers.xsd
|
||||||
|
|
||||||
# VS Code files for those working on multiple tools
|
# VS Code files for those working on multiple tools
|
||||||
.vscode/*
|
|
||||||
!.vscode/settings.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/extensions.json
|
|
||||||
*.code-workspace
|
*.code-workspace
|
||||||
|
|
||||||
# Local History for Visual Studio Code
|
# Local History for Visual Studio Code
|
||||||
.history/
|
|
||||||
|
|
||||||
# Windows Installer files from build outputs
|
# Windows Installer files from build outputs
|
||||||
*.cab
|
*.cab
|
||||||
@ -2221,3 +2213,18 @@ FodyWeavers.xsd
|
|||||||
/vendor/goodboyalex/php_components_pack/
|
/vendor/goodboyalex/php_components_pack/
|
||||||
/.idea/php-test-framework.xml
|
/.idea/php-test-framework.xml
|
||||||
/.idea/inspectionProfiles/Project_Default.xml
|
/.idea/inspectionProfiles/Project_Default.xml
|
||||||
|
/vendor/phpunit/phpunit/schema/12.2.xsd
|
||||||
|
/vendor/phpunit/phpunit/src/TextUI/Configuration/BootstrapLoader.php
|
||||||
|
/vendor/phpunit/phpunit/src/TextUI/Configuration/Exception/BootstrapScriptDoesNotExistException.php
|
||||||
|
/vendor/phpunit/phpunit/src/TextUI/Configuration/Exception/BootstrapScriptException.php
|
||||||
|
/vendor/phpunit/phpunit/ChangeLog-12.3.md
|
||||||
|
/vendor/phpunit/phpunit/src/Event/Events/TestRunner/ChildProcessErrored.php
|
||||||
|
/vendor/phpunit/phpunit/src/Event/Events/TestRunner/ChildProcessErroredSubscriber.php
|
||||||
|
/vendor/phpunit/phpunit/src/TextUI/Output/Default/ProgressPrinter/Subscriber/ChildProcessErroredSubscriber.php
|
||||||
|
/vendor/phpunit/phpunit/src/Runner/CodeCoverageInitializationStatus.php
|
||||||
|
/vendor/phpunit/phpunit/src/Framework/Attributes/IgnorePhpunitWarnings.php
|
||||||
|
/vendor/phpunit/phpunit/src/Metadata/IgnorePhpunitWarnings.php
|
||||||
|
/vendor/phpunit/phpunit/src/Metadata/Api/ProvidedData.php
|
||||||
|
/vendor/phpunit/phpunit/src/Framework/Attributes/TestDoxFormatter.php
|
||||||
|
/vendor/phpunit/phpunit/src/Metadata/TestDoxFormatter.php
|
||||||
|
/vendor/phpunit/phpunit/src/Framework/Attributes/TestDoxFormatterExternal.php
|
@ -31,15 +31,22 @@
|
|||||||
*/
|
*/
|
||||||
public ?Closure $ConvertFromDB;
|
public ?Closure $ConvertFromDB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Closure|null Метод сравнения типов.
|
||||||
|
*/
|
||||||
|
public ?Closure $Compare;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Конструктор.
|
* Конструктор.
|
||||||
*
|
*
|
||||||
* @param callable|null $fromType Метод конвертации из типа для заполнения таблицы базы данных.
|
* @param callable|null $fromType Метод конвертации из типа для заполнения таблицы базы данных.
|
||||||
* @param callable|null $toType Метод конвертации в тип для заполнения таблицы базы данных.
|
* @param callable|null $toType Метод конвертации в тип для заполнения таблицы базы данных.
|
||||||
|
* @param callable|null $compare Метод сравнения типов.
|
||||||
*/
|
*/
|
||||||
public function __construct (?callable $fromType = null, ?callable $toType = null)
|
public function __construct (?callable $fromType = null, ?callable $toType = null, ?callable $compare = null)
|
||||||
{
|
{
|
||||||
$this->ConvertToDB = $fromType;
|
$this->ConvertToDB = $fromType;
|
||||||
$this->ConvertFromDB = $toType;
|
$this->ConvertFromDB = $toType;
|
||||||
|
$this->Compare = $compare;
|
||||||
}
|
}
|
||||||
}
|
}
|
92
sources/classes/DBItemProperty.php
Normal file
92
sources/classes/DBItemProperty.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\classes;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use goodboyalex\php_components_pack\extensions\StringExtension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс свойства класса, реализующего интерфейс IDBItem.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_db_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class DBItemProperty
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string $Name Имя свойства.
|
||||||
|
*/
|
||||||
|
public string $Name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var mixed $Value Значение свойства (ещё не конвертированное!).
|
||||||
|
*/
|
||||||
|
public mixed $Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string $FieldName Имя поля в таблице БД.
|
||||||
|
*/
|
||||||
|
public string $FieldName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool $IsPrimaryKey Признак того, что свойство является первичным ключом.
|
||||||
|
*/
|
||||||
|
public bool $IsPrimaryKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool $IsIgnored Признак того, что свойство игнорируется при сохранении в / загрузке из БД.
|
||||||
|
*/
|
||||||
|
public bool $IsIgnored;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Closure $ConvertToDB Конвертер значения свойства в значение поля БД.
|
||||||
|
*/
|
||||||
|
public Closure $ConvertToDB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Closure $ConvertFromDB Конвертер значения поля БД в значение свойства.
|
||||||
|
*/
|
||||||
|
public Closure $ConvertFromDB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Closure $Compare Функция сравнения значений свойства.
|
||||||
|
*/
|
||||||
|
public Closure $Compare;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор.
|
||||||
|
*
|
||||||
|
* @param string $name Имя свойства.
|
||||||
|
* @param mixed|null $value Значение свойства (ещё не конвертированное!).
|
||||||
|
* @param string $fieldName Имя поля в таблице БД.
|
||||||
|
* @param bool $isPrimaryKey Признак того, что свойство является первичным ключом.
|
||||||
|
* @param bool $isIgnored Признак того, что свойство игнорируется при сохранении в / загрузке из БД.
|
||||||
|
* @param callable|null $ConvertToDB Конвертер значения свойства в значение поля БД.
|
||||||
|
* @param Closure|null $ConvertFromDB Конвертер значения поля БД в значение свойства.
|
||||||
|
* @param Closure|null $Compare Функция сравнения значений свойства.
|
||||||
|
*/
|
||||||
|
public function __construct (string $name = '', mixed $value = null, string $fieldName = '',
|
||||||
|
bool $isPrimaryKey = false, bool $isIgnored = false, ?callable $ConvertToDB = null,
|
||||||
|
?Closure $ConvertFromDB = null, ?Closure $Compare = null)
|
||||||
|
{
|
||||||
|
// Установка значений
|
||||||
|
// - установка имени свойства
|
||||||
|
$this->Name = $name;
|
||||||
|
// - установка значения свойства (ещё не конвертированного)
|
||||||
|
$this->Value = $value;
|
||||||
|
// - установка имени поля в таблице БД
|
||||||
|
$this->FieldName = StringExtension::IsNullOrWhitespace($fieldName) ? $name : $fieldName;
|
||||||
|
// - установка признака того, что свойство является первичным ключом
|
||||||
|
$this->IsPrimaryKey = $isPrimaryKey;
|
||||||
|
// - установка признака того, что свойство игнорируется при сохранении в / загрузке из БД
|
||||||
|
$this->IsIgnored = $isIgnored;
|
||||||
|
// - установка конвертеров значения свойства в значение поля БД
|
||||||
|
$this->ConvertToDB = $ConvertToDB ?? fn (mixed $value): mixed => $value;
|
||||||
|
// - установка конвертеров значения поля БД в значение свойства
|
||||||
|
$this->ConvertFromDB = $ConvertFromDB ?? fn (mixed $value): mixed => $value;
|
||||||
|
// - установка функции сравнения значений свойства
|
||||||
|
$this->Compare = $Compare ?? fn (mixed $value1, mixed $value2): bool => $value1 == $value2;
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@
|
|||||||
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
use goodboyalex\php_db_components_pack\enums\DBDriver;
|
||||||
use goodboyalex\php_db_components_pack\models\DBConfig;
|
use goodboyalex\php_db_components_pack\models\DBConfig;
|
||||||
use goodboyalex\php_db_components_pack\traits\Database\DatabaseCountExist;
|
use goodboyalex\php_db_components_pack\traits\Database\DatabaseCountExist;
|
||||||
|
use goodboyalex\php_db_components_pack\traits\Database\DatabaseDelete;
|
||||||
use goodboyalex\php_db_components_pack\traits\Database\DatabaseGet;
|
use goodboyalex\php_db_components_pack\traits\Database\DatabaseGet;
|
||||||
use goodboyalex\php_db_components_pack\traits\Database\DatabaseInsert;
|
use goodboyalex\php_db_components_pack\traits\Database\DatabaseInsert;
|
||||||
use goodboyalex\php_db_components_pack\traits\Database\DatabaseQueryExecute;
|
use goodboyalex\php_db_components_pack\traits\Database\DatabaseQueryExecute;
|
||||||
@ -150,48 +151,9 @@
|
|||||||
// Обновление записей
|
// Обновление записей
|
||||||
use DatabaseUpdate;
|
use DatabaseUpdate;
|
||||||
|
|
||||||
|
// Удаление записей
|
||||||
|
use DatabaseDelete;
|
||||||
|
|
||||||
// Приватные методы
|
// Приватные методы
|
||||||
use DatabaseSpecial;
|
use DatabaseSpecial;
|
||||||
|
|
||||||
/**
|
|
||||||
* Удаляет строки по условию.
|
|
||||||
*
|
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
}
|
}
|
64
sources/traits/Database/DatabaseDelete.php
Normal file
64
sources/traits/Database/DatabaseDelete.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @noinspection SqlNoDataSourceInspection
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\traits\Database;
|
||||||
|
|
||||||
|
use goodboyalex\php_db_components_pack\classes\ConditionBuilder;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Трейт для удаления записей в таблице базы данных.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_db_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
* @see PDO
|
||||||
|
*/
|
||||||
|
trait DatabaseDelete
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Удаляет строки по условию.
|
||||||
|
*
|
||||||
|
* @param string $table Имя таблицы.
|
||||||
|
* @param ConditionBuilder $where Массив условий.
|
||||||
|
*
|
||||||
|
* @return bool Результат выполнения.
|
||||||
|
*/
|
||||||
|
public function Delete (string $table, ConditionBuilder $where): bool
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Получаю SQL-запрос и параметры для where.
|
||||||
|
*
|
||||||
|
* @var string $sql_where SQL-запрос для where.
|
||||||
|
* @var array $params Параметры запроса.
|
||||||
|
*/
|
||||||
|
[$sql_where, $params] = $where->Build();
|
||||||
|
|
||||||
|
// Создаю запрос
|
||||||
|
$sql = "DELETE FROM $this->DBSignOpen$table$this->DBSignClose";
|
||||||
|
|
||||||
|
// Если заданы 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;
|
||||||
|
}
|
||||||
|
}
|
@ -7,17 +7,18 @@
|
|||||||
namespace goodboyalex\php_db_components_pack\traits\Database;
|
namespace goodboyalex\php_db_components_pack\traits\Database;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use goodboyalex\php_components_pack\classes\ObjectArray;
|
||||||
use goodboyalex\php_db_components_pack\attributes\ConvertToDB;
|
use goodboyalex\php_db_components_pack\attributes\ConvertToDB;
|
||||||
use goodboyalex\php_db_components_pack\attributes\FieldName;
|
use goodboyalex\php_db_components_pack\attributes\FieldName;
|
||||||
use goodboyalex\php_db_components_pack\attributes\IgnoredInDB;
|
use goodboyalex\php_db_components_pack\attributes\IgnoredInDB;
|
||||||
use goodboyalex\php_db_components_pack\attributes\PrimaryKey;
|
use goodboyalex\php_db_components_pack\attributes\PrimaryKey;
|
||||||
use goodboyalex\php_db_components_pack\classes\ConditionBuilder;
|
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\enums\DBOperation;
|
||||||
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
||||||
use PDO;
|
use PDO;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
use ReflectionException;
|
use ReflectionException;
|
||||||
use ReflectionProperty;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Трейт для функций поддержки для работы с базой данных.
|
* Трейт для функций поддержки для работы с базой данных.
|
||||||
@ -44,73 +45,45 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получает публичные свойства класса и их значения.
|
* Разбирает объект на свойства.
|
||||||
*
|
*
|
||||||
* @param object $obj Класс.
|
* @param IDBItem $source Объект со свойствами.
|
||||||
|
* @param DBOperation $operation Текущая операция.
|
||||||
*
|
*
|
||||||
* @return array Массив публичных свойств и их значений.
|
* @return ObjectArray Массив свойств и их значений класса, который реализует интерфейс IDBItem.
|
||||||
*/
|
*/
|
||||||
private static function GetPublicProperties (object $obj): array
|
private static function GetProperties (IDBItem $source, DBOperation $operation): ObjectArray
|
||||||
{
|
{
|
||||||
// Создаю массив свойств
|
// Создаю массив свойств
|
||||||
$result = [];
|
$result = new ObjectArray();
|
||||||
|
|
||||||
// Получаю массив свойств
|
// Получаю массив свойств
|
||||||
$properties = get_class_vars(get_class($obj));
|
$properties = get_class_vars(get_class($source));
|
||||||
|
|
||||||
// Для каждого свойства
|
// Для каждого свойства
|
||||||
foreach ($properties as $key => $value) {
|
foreach ($properties as $key => $value) {
|
||||||
// - пропускаю не свойства
|
// - пропускаю не свойства
|
||||||
if (!property_exists($obj, $key))
|
if (!property_exists($source, $key))
|
||||||
// -- пропускаю
|
// -- пропускаю
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// - получаю рефлексию
|
// - получаю рефлексию класса
|
||||||
$rProperty = new ReflectionProperty($obj, $key);
|
|
||||||
|
|
||||||
// - пропускаю не публичные свойства
|
|
||||||
if (!$rProperty->isPublic())
|
|
||||||
// -- пропускаю
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// - добавляю в массив свойство и его значение
|
|
||||||
$result[$key] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Возвращаю результат
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Получает первичные ключи класса.
|
|
||||||
*
|
|
||||||
* @param IDBItem $source Класс.
|
|
||||||
* @param DBOperation $operation Текущая операция.
|
|
||||||
*
|
|
||||||
* @return array Массив первичных ключей и их значений.
|
|
||||||
*/
|
|
||||||
private function FindPrimaryKeys (IDBItem $source, DBOperation $operation): array
|
|
||||||
{
|
|
||||||
// Создаю массив первичных ключей
|
|
||||||
$pKeys = [];
|
|
||||||
|
|
||||||
// Получаю массив свойств
|
|
||||||
$properties = self::GetPublicProperties($source);
|
|
||||||
|
|
||||||
// Для каждого свойства
|
|
||||||
foreach ($properties as $key => $value) {
|
|
||||||
// - получаю рефлексию
|
|
||||||
// - для класса
|
|
||||||
$reflectedClass = new ReflectionClass(get_class($source));
|
$reflectedClass = new ReflectionClass(get_class($source));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// - для свойства
|
// - получаю рефлексию свойства
|
||||||
$reflectionProperty = $reflectedClass->getProperty($key);
|
$reflectionProperty = $reflectedClass->getProperty($key);
|
||||||
}
|
}
|
||||||
catch (ReflectionException) {
|
catch (ReflectionException) {
|
||||||
// - если ошибка, то вывожу пустой массив
|
// - если ошибка, то вывожу пустой массив
|
||||||
return [];
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - пропускаю не публичные свойства
|
||||||
|
if (!$reflectionProperty->isPublic())
|
||||||
|
// -- пропускаю
|
||||||
|
continue;
|
||||||
|
|
||||||
// - получаю атрибуты
|
// - получаю атрибуты
|
||||||
$attributes = $reflectionProperty->getAttributes();
|
$attributes = $reflectionProperty->getAttributes();
|
||||||
|
|
||||||
@ -121,10 +94,8 @@
|
|||||||
*/
|
*/
|
||||||
$pkAttr = self::FindAttribute($attributes, PrimaryKey::class);
|
$pkAttr = self::FindAttribute($attributes, PrimaryKey::class);
|
||||||
|
|
||||||
// - если на свойстве нет атрибута первичного ключа
|
// - это первичный ключ?
|
||||||
if ($pkAttr === null)
|
$isPrimary = $pkAttr !== null;
|
||||||
// -- то пропускаю
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Фильтруем поля, игнорируемые для данной операции
|
* Фильтруем поля, игнорируемые для данной операции
|
||||||
@ -134,22 +105,42 @@
|
|||||||
$ignoreAttr = self::FindAttribute($attributes, IgnoredInDB::class);
|
$ignoreAttr = self::FindAttribute($attributes, IgnoredInDB::class);
|
||||||
|
|
||||||
// - если поле игнорируется
|
// - если поле игнорируется
|
||||||
if ($ignoreAttr !== null) {
|
$isIgnore = $ignoreAttr !== null
|
||||||
// -- то проверяю, игнорируется ли данное поле
|
&& $ignoreAttr->IgnoredOperations->IsExist(fn (DBOperation $oper)
|
||||||
$isIgnore = $ignoreAttr->IgnoredOperations->IsExist(fn (DBOperation $oper) => $oper == $operation);
|
=> $oper == $operation);
|
||||||
|
|
||||||
// -- если игнорируется
|
|
||||||
if ($isIgnore)
|
|
||||||
// --- то пропускаю
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - добавляю первичный ключ и его значение
|
/**
|
||||||
$pKeys[$key] = $value;
|
* Получаю значение имени поля
|
||||||
|
*
|
||||||
|
* @var FieldName|null $fieldNameAttr Атрибут имени поля.
|
||||||
|
*/
|
||||||
|
$fieldNameAttr = self::FindAttribute($attributes, FieldName::class);
|
||||||
|
|
||||||
|
// Если есть атрибут имени поля, то беру его имя, иначе беру имя свойства
|
||||||
|
$fieldName = $fieldNameAttr !== null ? $fieldNameAttr->FieldName : "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Преобразование типа.
|
||||||
|
*
|
||||||
|
* @var ConvertToDB|null $convertAttr Атрибут конвертации.
|
||||||
|
*/
|
||||||
|
$convertAttr = self::FindAttribute($attributes, ConvertToDB::class);
|
||||||
|
|
||||||
|
// - получаю функцию конвертации и сравнения
|
||||||
|
$converterToDB = $convertAttr?->ConvertToDB;
|
||||||
|
$converterFromDB = $convertAttr?->ConvertFromDB;
|
||||||
|
$compareFunc = $convertAttr?->Compare;
|
||||||
|
|
||||||
|
// - создаю объект свойства
|
||||||
|
$item = new DBItemProperty($key, $value, $fieldName, $isPrimary, $isIgnore, $converterToDB,
|
||||||
|
$converterFromDB, $compareFunc);
|
||||||
|
|
||||||
|
// - добавляю в массив
|
||||||
|
$result[] = $item;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Возвращаю найденные ключи
|
// Возвращаю результат
|
||||||
return $pKeys;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -165,70 +156,25 @@
|
|||||||
$result = [];
|
$result = [];
|
||||||
|
|
||||||
// Получаю массив свойств
|
// Получаю массив свойств
|
||||||
$properties = self::GetPublicProperties($source);
|
$properties = self::GetProperties($source, $operation);
|
||||||
|
|
||||||
// Для каждого свойства
|
/**
|
||||||
foreach ($properties as $key => $value) {
|
* Для каждого свойства...
|
||||||
// Получаю рефлексию
|
*
|
||||||
// - для класса
|
* @var DBItemProperty $property Свойство.
|
||||||
$reflectedClass = new ReflectionClass(get_class($source));
|
*/
|
||||||
try {
|
foreach ($properties as $property) {
|
||||||
// - для свойства
|
// - пропускаю игнорируемые поля
|
||||||
$reflectionProperty = $reflectedClass->getProperty($key);
|
if ($property->IsIgnored)
|
||||||
}
|
continue;
|
||||||
catch (ReflectionException $e) {
|
|
||||||
// - если ошибка, то вывожу и выходим
|
|
||||||
$this->HandleException($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - получаю атрибуты
|
// - получаю значение имени поля
|
||||||
$attributes = $reflectionProperty->getAttributes();
|
$fieldName = $property->FieldName;
|
||||||
|
|
||||||
/**
|
// - преобразую тип
|
||||||
* Фильтруем поля, игнорируемые для данной операции
|
$value = call_user_func($property->ConvertToDB, $property->Value);
|
||||||
*
|
|
||||||
* @var IgnoredInDB|null $ignoreAttr Атрибут игнорирования.
|
|
||||||
*/
|
|
||||||
$ignoreAttr = self::FindAttribute($attributes, IgnoredInDB::class);
|
|
||||||
|
|
||||||
// - если поле игнорируется
|
// - добавляю в массив
|
||||||
if ($ignoreAttr !== null) {
|
|
||||||
// -- то проверяю, игнорируется ли данное поле
|
|
||||||
$isIgnore = $ignoreAttr->IgnoredOperations->IsExist(fn (DBOperation $oper) => $oper == $operation);
|
|
||||||
|
|
||||||
// -- если игнорируется
|
|
||||||
if ($isIgnore)
|
|
||||||
// --- то пропускаю
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Получаю значение имени поля
|
|
||||||
*
|
|
||||||
* @var FieldName|null $fieldNameAttr Атрибут имени поля.
|
|
||||||
*/
|
|
||||||
$fieldNameAttr = self::FindAttribute($attributes, FieldName::class);
|
|
||||||
|
|
||||||
// Если есть атрибут имени поля, то беру его имя, иначе беру имя свойства
|
|
||||||
$fieldName = $fieldNameAttr !== null ? $fieldNameAttr->FieldName : $key;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Преобразование типа.
|
|
||||||
*
|
|
||||||
* @var ConvertToDB|null $convertAttr Атрибут конвертации.
|
|
||||||
*/
|
|
||||||
$convertAttr = self::FindAttribute($attributes, ConvertToDB::class);
|
|
||||||
|
|
||||||
// Если есть атрибут конвертации
|
|
||||||
if ($convertAttr) {
|
|
||||||
// - то получаю значение функции конвертации
|
|
||||||
$converter = $convertAttr->ConvertToDB;
|
|
||||||
|
|
||||||
// - выполняю функцию конвертации
|
|
||||||
$value = call_user_func($converter, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Добавляю в массив
|
|
||||||
$result[$fieldName] = $value;
|
$result[$fieldName] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,66 +201,27 @@
|
|||||||
// Создаём объект желаемого класса
|
// Создаём объект желаемого класса
|
||||||
$class = new $className();
|
$class = new $className();
|
||||||
|
|
||||||
// Получаем публичные свойства класса
|
// Получаю свойства класса
|
||||||
try {
|
$properties = self::GetProperties($class, $operation);
|
||||||
$properties = new ReflectionClass($class)->getProperties(ReflectionProperty::IS_PUBLIC);
|
|
||||||
}
|
|
||||||
catch (ReflectionException $exception) {
|
|
||||||
// - в случае ошибки, обрабатываем её
|
|
||||||
$this->HandleException($exception, false);
|
|
||||||
|
|
||||||
// - и возвращаем null
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Массив отношений, содержащий имя поля, имя свойства, метод преобразования
|
// Массив отношений, содержащий имя поля, имя свойства, метод преобразования
|
||||||
$propertiesRelationship = [];
|
$propertiesRelationship = [];
|
||||||
|
|
||||||
// Для каждого свойства
|
/**
|
||||||
|
* Для каждого свойства...
|
||||||
|
*
|
||||||
|
* @var DBItemProperty $property Свойство.
|
||||||
|
*/
|
||||||
foreach ($properties as $property) {
|
foreach ($properties as $property) {
|
||||||
// - получаю атрибуты
|
// - пропускаю игнорируемые поля
|
||||||
$attributes = $property->getAttributes();
|
if ($property->IsIgnored)
|
||||||
|
continue;
|
||||||
|
|
||||||
/**
|
// - получаю имя поля
|
||||||
* Фильтруем поля, игнорируемые для данной операции
|
$fieldName = $property->FieldName;
|
||||||
*
|
|
||||||
* @var IgnoredInDB|null $ignoreAttr Атрибут игнорирования.
|
|
||||||
*/
|
|
||||||
$ignoreAttr = self::FindAttribute($attributes, IgnoredInDB::class);
|
|
||||||
|
|
||||||
// - если поле игнорируется
|
|
||||||
if ($ignoreAttr !== null) {
|
|
||||||
// -- то проверяю, игнорируется ли данное поле
|
|
||||||
$isIgnore = $ignoreAttr->IgnoredOperations->IsExist(fn (DBOperation $oper) => $oper == $operation);
|
|
||||||
|
|
||||||
// -- если игнорируется
|
|
||||||
if ($isIgnore)
|
|
||||||
// --- то пропускаю
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Получаю значение имени поля
|
|
||||||
*
|
|
||||||
* @var FieldName|null $fieldNameAttr Атрибут имени поля.
|
|
||||||
*/
|
|
||||||
$fieldNameAttr = self::FindAttribute($attributes, FieldName::class);
|
|
||||||
|
|
||||||
// - если есть атрибут имени поля, то беру его имя, иначе беру имя свойства
|
|
||||||
$fieldName = $fieldNameAttr !== null ? $fieldNameAttr->FieldName : $property->getName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Преобразование типа.
|
|
||||||
*
|
|
||||||
* @var ConvertToDB|null $convertAttr Атрибут конвертации.
|
|
||||||
*/
|
|
||||||
$convertAttr = self::FindAttribute($attributes, ConvertToDB::class);
|
|
||||||
|
|
||||||
// - если есть атрибут конвертации, то получаю значение функции конвертации, иначе null
|
|
||||||
$converterFunc = ($convertAttr) ? $convertAttr->ConvertFromDB : null;
|
|
||||||
|
|
||||||
// - добавляю в массив отношений
|
// - добавляю в массив отношений
|
||||||
$propertiesRelationship[$fieldName] = [$property->getName(), $converterFunc];
|
$propertiesRelationship[$fieldName] = [$property->Name, $property->ConverterFromDB];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проходим элементы массива из БД
|
// Проходим элементы массива из БД
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
namespace goodboyalex\php_db_components_pack\traits\Database;
|
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\ConditionBuilder;
|
||||||
|
use goodboyalex\php_db_components_pack\classes\DBItemProperty;
|
||||||
use goodboyalex\php_db_components_pack\enums\DBOperation;
|
use goodboyalex\php_db_components_pack\enums\DBOperation;
|
||||||
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
||||||
use PDO;
|
use PDO;
|
||||||
@ -25,48 +27,128 @@
|
|||||||
* Заменяет данные в строке базы данных.
|
* Заменяет данные в строке базы данных.
|
||||||
*
|
*
|
||||||
* @param string $table Имя таблицы.
|
* @param string $table Имя таблицы.
|
||||||
* @param array $set Массив данных для замены
|
* @param IDBItem $item Обновляемый объект.
|
||||||
* @param array $where Массив условий
|
|
||||||
*
|
*
|
||||||
* @return bool Результат выполнения
|
* @return bool Результат выполнения.
|
||||||
*/
|
*/
|
||||||
public function UpdateOld (string $table, array $set, array $where = []): bool
|
public function Update (string $table, IDBItem $item): bool
|
||||||
{
|
{
|
||||||
// Создаю массив параметров
|
// Получаю свойства объекта
|
||||||
$params_set = [];
|
$properties = self::GetProperties($item, DBOperation::Update);
|
||||||
|
|
||||||
// Строковая интерпретация массива для изменения
|
// Получаю первичные ключи объекта
|
||||||
$sql_set = "";
|
$primaryKeys = $properties->GetRows(fn (DBItemProperty $property): bool => $property->IsPrimaryKey);
|
||||||
|
|
||||||
// Для каждых данных для изменения
|
// Создаю условие по первичным ключам (оно же и WHERE для обновления)
|
||||||
foreach ($set as $key => $value) {
|
$where = new ConditionBuilder();
|
||||||
// - получаю ключ 100%-но без ":" в начале
|
|
||||||
$set_key = $key[0] == ":" ? substr($key, 1) : $key;
|
// Для каждого первичного ключа
|
||||||
|
for ($i = 0; $i < $primaryKeys->Count(); $i++) {
|
||||||
|
// - если это не первая итерация
|
||||||
|
if ($i > 0)
|
||||||
|
// -- то добавляю AND
|
||||||
|
$where = $where->And();
|
||||||
|
|
||||||
// - добавляю префикс для 2 или более итерации
|
/**
|
||||||
$prefix = $sql_set == "" ? "" : ", ";
|
* Получаю свойство.
|
||||||
|
*
|
||||||
|
* @var DBItemProperty $property Свойство.
|
||||||
|
*/
|
||||||
|
$property = $primaryKeys[$i];
|
||||||
|
|
||||||
// - добавляю данные в sql_set
|
// - получаю ключ
|
||||||
$sql_set .= "$prefix$this->DBSignOpen$set_key$this->DBSignClose=:$set_key";
|
$whereKey = $property->FieldName;
|
||||||
|
|
||||||
// - добавляю данные в параметры
|
// - получаю значение ключа, конвертируя его в БД
|
||||||
$params_set[":" . $set_key] = $value;
|
$whereValue = call_user_func($property->ConvertToDB, $property->Value);
|
||||||
|
|
||||||
|
// - добавляю условие в WHERE
|
||||||
|
$where = $where->WhereEquals($whereKey, $whereValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обработанные параметры
|
// Получаю запись из базы данных
|
||||||
$params_where = [];
|
$dbItem = $this->GetRow($table, $where, className: get_class($item));
|
||||||
|
|
||||||
// Строковая интерпретация массива условий
|
// Если запись не найдена
|
||||||
$sql_where = $this->PrepareQueryWhere(where: $where, params: $params_where);
|
if ($dbItem === false)
|
||||||
|
// - то и общий результат - false
|
||||||
|
return false;
|
||||||
|
|
||||||
// Создаю параметры
|
// Создаю массив параметров для обновления
|
||||||
$params = array_merge($params_set, $params_where);
|
$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";
|
$sql = "UPDATE $this->DBSignOpen$table$this->DBSignClose SET $sql_set";
|
||||||
|
|
||||||
// Если заданы where-параметры
|
// Если заданы where-параметры
|
||||||
if (count($where) > 0)
|
if ($where->Count() > 0)
|
||||||
// - то добавляю их
|
// - то добавляю их
|
||||||
$sql .= " WHERE $sql_where";
|
$sql .= " WHERE $sql_where";
|
||||||
|
|
||||||
@ -87,79 +169,45 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Update (string $table, IDBItem $item): bool
|
/**
|
||||||
|
* Обновляет несколько записей в таблице базы данных.
|
||||||
|
*
|
||||||
|
* @param string $table Имя таблицы.
|
||||||
|
* @param IDBItem ...$items Массив обновляемых объектов.
|
||||||
|
*
|
||||||
|
* @return bool Результат выполнения.
|
||||||
|
*/
|
||||||
|
public function UpdateMany (string $table, IDBItem ...$items): bool
|
||||||
{
|
{
|
||||||
$primaryKeys = $this->FindPrimaryKeys($item, DBOperation::Update);
|
// Инициализирую транзакцию
|
||||||
|
$this->InitTransaction();
|
||||||
|
|
||||||
$pk_keys = array_keys($primaryKeys);
|
// Подготавливаю массив последних id
|
||||||
|
$resultArray = [];
|
||||||
|
|
||||||
$where = new ConditionBuilder();
|
try {
|
||||||
|
// Для каждого источника
|
||||||
for ($i = 0; $i < count($primaryKeys); $i++) {
|
foreach ($items as $item)
|
||||||
if ($i > 0)
|
// - вставляю строку
|
||||||
$where = $where->And();
|
$resultArray[] = $this->Update($table, $item);
|
||||||
|
|
||||||
$whereKey = $pk_keys[$i];
|
// Если вставка успешна, то подтверждаю транзакцию
|
||||||
|
$this->Commit();
|
||||||
|
}
|
||||||
|
catch (Exception) {
|
||||||
|
// - если ошибка, то откатываю транзакцию
|
||||||
|
$this->RollBack();
|
||||||
|
|
||||||
$whereValue = $primaryKeys[$whereKey];
|
// - и вывожу ошибку
|
||||||
|
return false;
|
||||||
$where = $where->WhereEquals($whereKey, $whereValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$dbItem = $this->GetRow($table, $where, className: get_class($item));
|
// Если есть ошибка
|
||||||
|
if (array_any($resultArray, fn (bool $value): bool => $value === false))
|
||||||
// Создаю массив параметров
|
// - то вывожу ошибку
|
||||||
$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;
|
return false;
|
||||||
|
|
||||||
// Если изменено 0 строк
|
// Так как мы дошли до сюда, то это успех! Вывожу результат
|
||||||
if ($count === 0)
|
|
||||||
// - то и общий результат - false
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Вывожу результат -- успех
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user