20250802-1

This commit is contained in:
2025-08-02 21:20:32 +03:00
parent 4ec8ccc089
commit a80c4e6f65
7 changed files with 402 additions and 315 deletions

View File

@@ -7,17 +7,18 @@
namespace goodboyalex\php_db_components_pack\traits\Database;
use Exception;
use goodboyalex\php_components_pack\classes\ObjectArray;
use goodboyalex\php_db_components_pack\attributes\ConvertToDB;
use goodboyalex\php_db_components_pack\attributes\FieldName;
use goodboyalex\php_db_components_pack\attributes\IgnoredInDB;
use goodboyalex\php_db_components_pack\attributes\PrimaryKey;
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;
use ReflectionClass;
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) {
// - пропускаю не свойства
if (!property_exists($obj, $key))
if (!property_exists($source, $key))
// -- пропускаю
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));
try {
// - для свойства
// - получаю рефлексию свойства
$reflectionProperty = $reflectedClass->getProperty($key);
}
catch (ReflectionException) {
// - если ошибка, то вывожу пустой массив
return [];
return $result;
}
// - пропускаю не публичные свойства
if (!$reflectionProperty->isPublic())
// -- пропускаю
continue;
// - получаю атрибуты
$attributes = $reflectionProperty->getAttributes();
@@ -121,10 +94,8 @@
*/
$pkAttr = self::FindAttribute($attributes, PrimaryKey::class);
// - если на свойстве нет атрибута первичного ключа
if ($pkAttr === null)
// -- то пропускаю
continue;
// - это первичный ключ?
$isPrimary = $pkAttr !== null;
/**
* Фильтруем поля, игнорируемые для данной операции
@@ -134,22 +105,42 @@
$ignoreAttr = self::FindAttribute($attributes, IgnoredInDB::class);
// - если поле игнорируется
if ($ignoreAttr !== null) {
// -- то проверяю, игнорируется ли данное поле
$isIgnore = $ignoreAttr->IgnoredOperations->IsExist(fn (DBOperation $oper) => $oper == $operation);
// -- если игнорируется
if ($isIgnore)
// --- то пропускаю
continue;
}
$isIgnore = $ignoreAttr !== null
&& $ignoreAttr->IgnoredOperations->IsExist(fn (DBOperation $oper)
=> $oper == $operation);
// - добавляю первичный ключ и его значение
$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 = [];
// Получаю массив свойств
$properties = self::GetPublicProperties($source);
$properties = self::GetProperties($source, $operation);
// Для каждого свойства
foreach ($properties as $key => $value) {
// Получаю рефлексию
// - для класса
$reflectedClass = new ReflectionClass(get_class($source));
try {
// - для свойства
$reflectionProperty = $reflectedClass->getProperty($key);
}
catch (ReflectionException $e) {
// - если ошибка, то вывожу и выходим
$this->HandleException($e);
}
/**
* Для каждого свойства...
*
* @var DBItemProperty $property Свойство.
*/
foreach ($properties as $property) {
// - пропускаю игнорируемые поля
if ($property->IsIgnored)
continue;
// - получаю атрибуты
$attributes = $reflectionProperty->getAttributes();
// - получаю значение имени поля
$fieldName = $property->FieldName;
/**
* Фильтруем поля, игнорируемые для данной операции
*
* @var IgnoredInDB|null $ignoreAttr Атрибут игнорирования.
*/
$ignoreAttr = self::FindAttribute($attributes, IgnoredInDB::class);
// - преобразую тип
$value = call_user_func($property->ConvertToDB, $property->Value);
// - если поле игнорируется
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;
}
@@ -255,66 +201,27 @@
// Создаём объект желаемого класса
$class = new $className();
// Получаем публичные свойства класса
try {
$properties = new ReflectionClass($class)->getProperties(ReflectionProperty::IS_PUBLIC);
}
catch (ReflectionException $exception) {
// - в случае ошибки, обрабатываем её
$this->HandleException($exception, false);
// - и возвращаем null
return null;
}
// Получаю свойства класса
$properties = self::GetProperties($class, $operation);
// Массив отношений, содержащий имя поля, имя свойства, метод преобразования
$propertiesRelationship = [];
// Для каждого свойства
/**
* Для каждого свойства...
*
* @var DBItemProperty $property Свойство.
*/
foreach ($properties as $property) {
// - получаю атрибуты
$attributes = $property->getAttributes();
// - пропускаю игнорируемые поля
if ($property->IsIgnored)
continue;
/**
* Фильтруем поля, игнорируемые для данной операции
*
* @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;
// - получаю имя поля
$fieldName = $property->FieldName;
// - добавляю в массив отношений
$propertiesRelationship[$fieldName] = [$property->getName(), $converterFunc];
$propertiesRelationship[$fieldName] = [$property->Name, $property->ConverterFromDB];
}
// Проходим элементы массива из БД