20250731
This commit is contained in:
parent
45fb57981d
commit
2f3dd81d0a
37
sources/attributes/FieldName.php
Normal file
37
sources/attributes/FieldName.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Отключаю несущественные инспекции (из-за Attribute)
|
||||||
|
*
|
||||||
|
* @noinspection PhpMultipleClassDeclarationsInspection
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace goodboyalex\php_db_components_pack\attributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Атрибут указывающий имя поля в БД.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_db_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
#[Attribute(flags: Attribute::TARGET_PROPERTY)]
|
||||||
|
final readonly class FieldName
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string $FieldName Имя поля.
|
||||||
|
*/
|
||||||
|
public string $FieldName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор.
|
||||||
|
*
|
||||||
|
* @param string $fieldName Имя поля.
|
||||||
|
*/
|
||||||
|
public function __construct (string $fieldName)
|
||||||
|
{
|
||||||
|
$this->FieldName = $fieldName;
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use goodboyalex\php_components_pack\classes\Tuple;
|
use goodboyalex\php_components_pack\classes\Tuple;
|
||||||
|
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 PDOException;
|
use PDOException;
|
||||||
@ -28,20 +29,14 @@
|
|||||||
*
|
*
|
||||||
* @param string $table Имя таблицы.
|
* @param string $table Имя таблицы.
|
||||||
* @param IDBItem $row Модель или класс, реализующий интерфейс IDBItem, для вставки.
|
* @param IDBItem $row Модель или класс, реализующий интерфейс IDBItem, для вставки.
|
||||||
* @param array $options Массив дополнительных параметров. Может содержать следующие ключи:
|
|
||||||
*
|
*
|
||||||
* - <code>ignore: array</code> - игнорировать перечисленные поля. Когда массив пуст, то ничего
|
* @return mixed В случае успеха выведет: id созданной записи, -1, если запись создана, но id не получен
|
||||||
* игнорироваться не будет. По умолчанию - пустой массив.
|
|
||||||
* - <code>allow: array</code> - включать только перечисленные поля. Когда массив пуст, то все поля будут
|
|
||||||
* включены. По умолчанию - пустой массив.
|
|
||||||
*
|
|
||||||
* @return string|false В случае успеха выведет: id созданной записи, -1, если запись создана, но id не получен
|
|
||||||
* (глюк?) и false, если ошибка
|
* (глюк?) и false, если ошибка
|
||||||
*/
|
*/
|
||||||
public function Insert (string $table, IDBItem $row, array $options = []): string|false
|
public function Insert (string $table, IDBItem $row): mixed
|
||||||
{
|
{
|
||||||
// Подготавливаю запрос
|
// Подготавливаю запрос
|
||||||
[$sql, $params] = $this->PrepareInsertSQL($table, $row, $options);
|
[$sql, $params] = $this->PrepareInsertSQL($table, $row);
|
||||||
|
|
||||||
// Выполняю запрос
|
// Выполняю запрос
|
||||||
$count = $this->Execute($sql, $params);
|
$count = $this->Execute($sql, $params);
|
||||||
@ -115,10 +110,10 @@
|
|||||||
*
|
*
|
||||||
* @return Tuple Возвращает [запрос, параметры запроса].
|
* @return Tuple Возвращает [запрос, параметры запроса].
|
||||||
*/
|
*/
|
||||||
private function PrepareInsertSQL (string $table, IDBItem $row, array $options = []): Tuple
|
private function PrepareInsertSQL (string $table, IDBItem $row): Tuple
|
||||||
{
|
{
|
||||||
// Подготавливаю массив параметров
|
// Подготавливаю массив параметров
|
||||||
$params = $this->PrepareParamsArray(source: $row, options: $options);
|
$params = $this->PrepareParamsArray(source: $row, operation: DBOperation::Insert);
|
||||||
|
|
||||||
// Получаю ключи параметров
|
// Получаю ключи параметров
|
||||||
$keys = array_keys($params);
|
$keys = array_keys($params);
|
||||||
|
@ -7,10 +7,15 @@
|
|||||||
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\exceptions\TypeException;
|
use goodboyalex\php_db_components_pack\attributes\ConvertToDB;
|
||||||
use goodboyalex\php_components_pack\extensions\TypeExtension;
|
use goodboyalex\php_db_components_pack\attributes\FieldName;
|
||||||
|
use goodboyalex\php_db_components_pack\attributes\IgnoredInDB;
|
||||||
|
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 ReflectionException;
|
||||||
|
use ReflectionProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Трейт для функций поддержки для работы с базой данных.
|
* Трейт для функций поддержки для работы с базой данных.
|
||||||
@ -24,23 +29,143 @@
|
|||||||
trait DatabaseSpecial
|
trait DatabaseSpecial
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Добавляет параметр в массив.
|
* Подготавливает массив параметров для запроса.
|
||||||
*
|
*
|
||||||
* @param array $array Массив.
|
* @param array $array Массив.
|
||||||
* @param string $key Имя параметра.
|
|
||||||
* @param mixed $value Значение параметра.
|
|
||||||
*
|
*
|
||||||
* @return void
|
* @return array Массив с подготовленными параметрами.
|
||||||
*/
|
*/
|
||||||
private static function AddArrayItem (array &$array, string $key, mixed $value): void
|
private static function PrepareArray (array $array): array
|
||||||
{
|
{
|
||||||
// Если ключ параметра начинается с ":"
|
// Результирующий массив
|
||||||
if ($key[0] == ":")
|
$result = [];
|
||||||
// - то сразу добавляем его в результирующий массив
|
|
||||||
$array[$key] = $value;
|
// Для каждого элемента массива
|
||||||
else
|
foreach ($array as $key => $value)
|
||||||
// - в противном случае, предварительно добавим в имя ключа ":"
|
// - если ключ начинается с ":"
|
||||||
$array[':' . $key] = $value;
|
if ($key[0] == ":")
|
||||||
|
// - то сразу добавляем его в результирующий массив
|
||||||
|
$result[$key] = $value;
|
||||||
|
else
|
||||||
|
// - в противном случае, предварительно добавим в имя ключа ":"
|
||||||
|
$result[':' . $key] = $value;
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Находит атрибут в массиве.
|
||||||
|
*
|
||||||
|
* @param array $attrs Массив атрибутов.
|
||||||
|
* @param string $className Имя класса.
|
||||||
|
*
|
||||||
|
* @return object|null Объект атрибута или <code>null</code>
|
||||||
|
*/
|
||||||
|
private static function FindAttribute (array $attrs, string $className): ?object
|
||||||
|
{
|
||||||
|
return array_find($attrs, fn ($attr) => $attr->getName() === $className);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, является ли свойство публичным.
|
||||||
|
*
|
||||||
|
* @param object $obj Объект.
|
||||||
|
* @param string $propertyName Имя свойства.
|
||||||
|
*
|
||||||
|
* @return bool Возвращает <code>true</code>, если свойство публичное, иначе <code>false</code>.
|
||||||
|
*/
|
||||||
|
private static function IsPublicProperty (object $obj, string $propertyName): bool
|
||||||
|
{
|
||||||
|
return property_exists($obj, $propertyName) && new ReflectionProperty($obj, $propertyName)->isPublic();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Подготавливает массив параметров
|
||||||
|
*
|
||||||
|
* @param IDBItem $source Объект со свойствами.
|
||||||
|
* @param DBOperation $operation Текущая операция.
|
||||||
|
*
|
||||||
|
* @return array|false Подготовленный массив параметров или false в случае ошибки
|
||||||
|
*/
|
||||||
|
private function PrepareParamsArray (IDBItem $source, DBOperation $operation): array|false
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Получаю массив свойств
|
||||||
|
$properties = get_class_vars(get_class($source));
|
||||||
|
|
||||||
|
// Для каждого свойства
|
||||||
|
foreach ($properties as $key => $value) {
|
||||||
|
// - пропускаю не публичные свойства
|
||||||
|
if (!self::IsPublicProperty($source, $key))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Получаю рефлексию
|
||||||
|
// - для класса
|
||||||
|
$reflectedClass = new ReflectionClass(get_class($source));
|
||||||
|
try {
|
||||||
|
// - для свойства
|
||||||
|
$reflectionProperty = $reflectedClass->getProperty($key);
|
||||||
|
}
|
||||||
|
catch (ReflectionException $e) {
|
||||||
|
// - если ошибка, то вывожу и выходим
|
||||||
|
$this->HandleException($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - получаю атрибуты
|
||||||
|
$attributes = $reflectionProperty->getAttributes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Фильтруем поля, игнорируемые для данной операции
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаю результат
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,79 +184,6 @@
|
|||||||
$onException($exception);
|
$onException($exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Подготавливает массив параметров
|
|
||||||
*
|
|
||||||
* @param IDBItem $source Объект со свойствами.
|
|
||||||
* @param bool $withId Добавлять ли id в массив.
|
|
||||||
* @param array $options Опции.
|
|
||||||
*
|
|
||||||
* @return array|false Подготовленный массив параметров или false в случае ошибки
|
|
||||||
*/
|
|
||||||
private function PrepareParamsArray (IDBItem $source, bool $withId = true, array $options = []): array|false
|
|
||||||
{
|
|
||||||
// Создаём результирующий массив
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
// Если есть игнорируемые или разрешенные свойства
|
|
||||||
if (!(count($options['ignore']) == 0 && count($options['allow']) == 0))
|
|
||||||
// -- то для каждого игнорируемого свойства
|
|
||||||
foreach ($options['ignored'] as $ignoredProperty)
|
|
||||||
// --- и если оно есть в массиве разрешенных
|
|
||||||
if (in_array($ignoredProperty, $options['allowed']))
|
|
||||||
// ---- то исключаю его из массива разрешенных
|
|
||||||
unset($options['allowed'][array_search($ignoredProperty, $options['allowed'])]);
|
|
||||||
|
|
||||||
// Получаю массив свойств
|
|
||||||
$properties = $source->ToSQL($withId);
|
|
||||||
|
|
||||||
// Для каждого элемента массива
|
|
||||||
foreach ($properties as $name => $value) {
|
|
||||||
// - если свойство игнорируется
|
|
||||||
if (in_array($name, $options['ignored']))
|
|
||||||
// -- пропускаю
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// - если свойство не разрешено
|
|
||||||
if (count($options['allowed']) > 0 && !in_array($name, $options['allowed']))
|
|
||||||
// -- пропускаю
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// - если свойство является объектом
|
|
||||||
if (is_object($source->$name)) {
|
|
||||||
try {
|
|
||||||
// -- пытаюсь преобразовать его в массив
|
|
||||||
self::AddArrayItem($result, $name, json_encode(TypeExtension::ToArray($source->$name),
|
|
||||||
JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
|
||||||
}
|
|
||||||
catch (TypeException) {
|
|
||||||
// -- если не получилось, то сериализую его
|
|
||||||
self::AddArrayItem($result, $name,
|
|
||||||
json_encode($source->$name, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- пропускаю
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - если свойство является массивом
|
|
||||||
if (is_array($source->$name)) {
|
|
||||||
// -- сериализую его
|
|
||||||
self::AddArrayItem($result, $name, json_encode($source->$name, JSON_UNESCAPED_UNICODE |
|
|
||||||
JSON_PRETTY_PRINT));
|
|
||||||
|
|
||||||
// -- пропускаю
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - иначе просто добавляю свойство в массив
|
|
||||||
self::AddArrayItem($result, $name, $source->$name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Вывожу результирующий массив
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Подготавливает массив столбцов для использования в базе данных
|
* Подготавливает массив столбцов для использования в базе данных
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user