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 goodboyalex\php_components_pack\classes\Tuple;
|
||||
use goodboyalex\php_db_components_pack\enums\DBOperation;
|
||||
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
@ -28,20 +29,14 @@
|
||||
*
|
||||
* @param string $table Имя таблицы.
|
||||
* @param IDBItem $row Модель или класс, реализующий интерфейс IDBItem, для вставки.
|
||||
* @param array $options Массив дополнительных параметров. Может содержать следующие ключи:
|
||||
*
|
||||
* - <code>ignore: array</code> - игнорировать перечисленные поля. Когда массив пуст, то ничего
|
||||
* игнорироваться не будет. По умолчанию - пустой массив.
|
||||
* - <code>allow: array</code> - включать только перечисленные поля. Когда массив пуст, то все поля будут
|
||||
* включены. По умолчанию - пустой массив.
|
||||
*
|
||||
* @return string|false В случае успеха выведет: id созданной записи, -1, если запись создана, но id не получен
|
||||
* @return mixed В случае успеха выведет: id созданной записи, -1, если запись создана, но id не получен
|
||||
* (глюк?) и 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);
|
||||
@ -115,10 +110,10 @@
|
||||
*
|
||||
* @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);
|
||||
|
@ -7,10 +7,15 @@
|
||||
namespace goodboyalex\php_db_components_pack\traits\Database;
|
||||
|
||||
use Exception;
|
||||
use goodboyalex\php_components_pack\exceptions\TypeException;
|
||||
use goodboyalex\php_components_pack\extensions\TypeExtension;
|
||||
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\enums\DBOperation;
|
||||
use goodboyalex\php_db_components_pack\interfaces\IDBItem;
|
||||
use PDO;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use ReflectionProperty;
|
||||
|
||||
/**
|
||||
* Трейт для функций поддержки для работы с базой данных.
|
||||
@ -24,23 +29,143 @@
|
||||
trait DatabaseSpecial
|
||||
{
|
||||
/**
|
||||
* Добавляет параметр в массив.
|
||||
* Подготавливает массив параметров для запроса.
|
||||
*
|
||||
* @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] == ":")
|
||||
// - то сразу добавляем его в результирующий массив
|
||||
$array[$key] = $value;
|
||||
else
|
||||
// - в противном случае, предварительно добавим в имя ключа ":"
|
||||
$array[':' . $key] = $value;
|
||||
// Результирующий массив
|
||||
$result = [];
|
||||
|
||||
// Для каждого элемента массива
|
||||
foreach ($array as $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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Подготавливает массив параметров
|
||||
*
|
||||
* @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