From 2afc439354c871fc92959a9884ca5eebd80d3bc0 Mon Sep 17 00:00:00 2001 From: User Date: Tue, 28 Jan 2025 03:31:47 +0300 Subject: [PATCH] 20250128#1 --- src/AbstractMysqlRepository.php | 128 +++++++++++++++++++----- src/AbstractRepository.php | 130 +++++++++++++------------ src/Mysql/MysqlRepositoryInterface.php | 71 +++++++++++--- src/RepositoryInterface.php | 15 +-- 4 files changed, 235 insertions(+), 109 deletions(-) diff --git a/src/AbstractMysqlRepository.php b/src/AbstractMysqlRepository.php index 079aafc..5151cbd 100644 --- a/src/AbstractMysqlRepository.php +++ b/src/AbstractMysqlRepository.php @@ -11,8 +11,11 @@ abstract class AbstractMysqlRepository extends AbstractRepository implements Mys public const DEBUG = false; public const TABLE = null; - public const ENTINY = null; + public const ENTITY = null; + private string $table; + private string $entity; + private bool $debug; public function __construct( public readonly MysqlStorageInterface $mysql @@ -42,27 +45,26 @@ abstract class AbstractMysqlRepository extends AbstractRepository implements Mys /** @inheritDoc */ - public function getEntityById(int $id, $require = false) { - $this->checkConst(); - if($result = $this->mysql->findById(static::TABLE, $id)) $out = $this->createFromData(static::ENTINY, $result); - if(empty($out) && $require) throw new RepositoryException("Запись не найдена"); + public function getEntityById(int $id, string $table = null): mixed { + if(!isset($table)) $table = $this->getTable(); + if($result = $this->mysql->findById($table, $id)) $out = $this->createFromData($this->getEntityClass(), $result); return $out ?? null; } /** @inheritDoc */ - public function saveEntity(EntityInterface $object) : mixed { - $this->checkConst(); + public function saveEntity(EntityInterface $object, string $table = null) : mixed { + if(!isset($table)) $table = $this->getTable(); $in = $this->getProperties($object, function ($value){ return (is_string($value)) ? $this->mysql->escapeStr($value) : $value; }); - if(static::DEBUG) {$this->getSaveDebug($object, $in, static::TABLE); exit;} + if($this->getDebug()) {$this->debug($object, $in, $table); exit;} try { - if (!empty($object->getId()) && !empty($this->mysql->findById(static::TABLE, $object->getId()))) { - $this->mysql->updateById(static::TABLE, $in, $object->getId()); + if (!empty($object->getId()) && !empty($this->mysql->findById($table, $object->getId()))) { + $this->mysql->updateById($table, $in, $object->getId()); return $object->getId(); } else { - $this->mysql->insert(static::TABLE, $in); + $this->mysql->insert($table, $in); return (is_string($object->getId())) ? $object->getId() : $this->mysql->mysql()->insert_id; } } catch (\Throwable $throwable) {throw new RepositoryException($throwable->getMessage());} @@ -70,10 +72,29 @@ abstract class AbstractMysqlRepository extends AbstractRepository implements Mys /** @inheritDoc */ - public function saveGroup(array $objects): array { + public function saveData(array $data, string $table = null, string $primaryKey = 'id') : mixed { + if(!isset($table)) $table = $this->getTable(); + $in = array_map(function ($value){ + return (is_string($value)) ? $this->mysql->escapeStr($value) : $value; + }, $data); + if($this->getDebug()) {$this->debug($data, $in, $table); exit;} + try { + if (!empty($data[$primaryKey]) && !empty($this->mysql->findById($table, $data[$primaryKey], $primaryKey))) { + $this->mysql->updateById($table, $in, $data[$primaryKey]); + return $data[$primaryKey]; + } else { + $this->mysql->insert($table, $in); + return (is_string($data[$primaryKey])) ? $data[$primaryKey] : $this->mysql->mysql()->insert_id; + } + } catch (\Throwable $throwable) {throw new RepositoryException($throwable->getMessage());} + } + + + /** @inheritDoc */ + public function saveEntityGroup(array $objects, string $table = null): array { try{ $this->mysql->mysql()->begin_transaction(); - foreach($objects as $object) $id[] = $this->saveEntity($object); + foreach($objects as $object) $id[] = $this->saveEntity($object, $table); $this->mysql->mysql()->commit(); return $id ?? []; } @@ -85,10 +106,25 @@ abstract class AbstractMysqlRepository extends AbstractRepository implements Mys /** @inheritDoc */ - public function deleteEntity(EntityInterface $object) : bool { - $this->checkConst(); + public function saveDataGroup(array $objects, string $table = null, string $primaryKey = 'id'): array { + try{ + $this->mysql->mysql()->begin_transaction(); + foreach($objects as $object) $id[] = $this->saveData($object, $table, $primaryKey); + $this->mysql->mysql()->commit(); + return $id ?? []; + } + catch (\Exception $exception){ + $this->mysql->mysql()->rollback(); + throw new RepositoryException($exception->getMessage()); + } + } + + + /** @inheritDoc */ + public function deleteEntity(EntityInterface $object, string $table = null) : bool { + if(!isset($table)) $table = $this->getTable(); if(!empty($object->getId())){ - return $this->mysql->deleteById(static::TABLE, $object->getId()); + return $this->mysql->deleteById($table, $object->getId()); } return false; } @@ -100,23 +136,63 @@ abstract class AbstractMysqlRepository extends AbstractRepository implements Mys } + /** @inheritDoc */ + public function setTable(string $table) : void { + $this->table = $table; + } + + + /** @inheritDoc */ + public function setEntity(string $entity) : void { + $this->entity = $entity; + } + + + /** @inheritDoc */ + public function setDebug(bool $debug) : void { + $this->debug = $debug; + } + + + /** + * @return string + * @throws RepositoryException + */ + private function getTable() : string { + if(!empty($this->table)) return $this->table; + if(!empty(static::TABLE)) return static::TABLE; + throw new RepositoryException("Имя таблицы не задано"); + } + + + /** + * @return string + * @throws RepositoryException + */ + private function getEntityClass() : string { + if(!empty($this->entity)) return $this->entity; + if(!empty(static::ENTITY)) return static::ENTITY; + throw new RepositoryException("Не указан объект"); + } + + + /** + * @return bool + */ + private function getDebug(): bool { + if(!empty($this->debug)) return $this->debug; + if(!empty(static::DEBUG)) return static::DEBUG; + return false; + } + /** * @param ...$arg * @return void */ - protected function getSaveDebug(...$arg) : void { + protected function debug(...$arg) : void { if(function_exists('dd')) dd(...$arg); if(function_exists('vdd')) vdd(...$arg); var_dump(...$arg); } - - /** - * @throws RepositoryException - */ - protected function checkConst(): void { - if(empty(static::TABLE)) throw new RepositoryException("Имя таблицы не задано"); - if(empty(static::ENTINY)) throw new RepositoryException("Не указан объект"); - } - } diff --git a/src/AbstractRepository.php b/src/AbstractRepository.php index f090996..9ebee24 100644 --- a/src/AbstractRepository.php +++ b/src/AbstractRepository.php @@ -12,16 +12,80 @@ abstract class AbstractRepository implements RepositoryInterface { static array $classes = []; /** @inheritDoc */ - public function createFromData(string $class, $data) : mixed { + public function createFromData(string $class, $data) : object { try { if(!isset(static::$classes[$class])) static::$classes[$class] = new ReflectionClass($class); - $object = new $class; + return $this->fillObject(static::$classes[$class], new $class, $data); + } + catch (ReflectionException $exception) { + throw new RepositoryException($exception->getMessage()); + } + } + + + /** @inheritDoc */ + public function updateFromData(object $object, array $data) : object { + try { + $class = get_class($object); + if(!isset(static::$classes[$class])) static::$classes[$class] = new ReflectionClass($class); + return $this->fillObject(static::$classes[$class], clone $object, $data, true); + } + catch (RepositoryException|ReflectionException $exception) { + throw new RepositoryException($exception->getMessage()); + } + } + + + /** + * @param object $object + * @param callable|null $method + * @return array + * @throws RepositoryException + */ + public function getProperties(object $object, callable $method = null) : array { + try{ + $class = get_class($object); + if(!isset(static::$classes[$class])) static::$classes[$class] = new ReflectionClass($class); /** @var ReflectionProperty $property */ - foreach (static::$classes[$class]->getProperties() as $property) { + foreach(static::$classes[$class]->getProperties() as $property){ + if(!$property->isInitialized($object)) continue; + if(static::$classes[$class]->hasMethod('get'.ucfirst($property->getName()))){ + $fieldValue[$property->getName()] = $object->{'get'.ucfirst($property->getName())}($property->getValue($object)); + } + elseif($property->hasType() && class_exists($property->getType()->getName()) && $property->getValue($object) instanceof ValueObjectInterface){ + $fieldValue[$property->getName()] = $property->getValue($object)->get(); + } + elseif(is_bool($property->getValue($object))){ + $fieldValue[$property->getName()] = (int) $property->getValue($object); + } + else $fieldValue[$property->getName()] = $property->getValue($object); + $fieldNameSnakeCase = strtolower(preg_replace("'([A-Z])'", "_$1", $property->getName())); + if(false !== $fieldValue[$property->getName()]) $out[$fieldNameSnakeCase] = $fieldValue[$property->getName()]; + } + return (isset($method)) ? array_map($method, $out ?? []) : $out ?? []; + } + catch (ReflectionException $exception) { + throw new RepositoryException($exception->getMessage()); + } + } + + + /** + * @param ReflectionClass $class + * @param object $object + * @param array $data + * @param bool $update + * @return mixed + * @throws RepositoryException + */ + private function fillObject(ReflectionClass $class, object $object, array $data, bool $update = false) : mixed { + try { + foreach($class->getProperties() as $property){ + if($update && !array_key_exists($property->getName(), $data) && !array_key_exists(strtolower(preg_replace("'([A-Z])'", "_$1", $property->getName())), $data)) continue; // data[propertyName] ?? data[property_name] ?? null $value = $data[$property->getName()] ?? $data[strtolower(preg_replace("'([A-Z])'", "_$1", $property->getName()))] ?? null; // если есть внутренний метод (приоритетная обработка) - if(static::$classes[$class]->hasMethod('set'.ucfirst($property->getName()))) $object->{'set'.ucfirst($property->getName())}($value); + if($class->hasMethod('set'.ucfirst($property->getName()))) $object->{'set'.ucfirst($property->getName())}($value); // Если тип свойства класс (valueObject) elseif($property->hasType() && class_exists($property->getType()->getName())) $object->{$property->getName()} = (is_object($value)) ? $value : new ($property->getType()->getName())($value); // если значения не пустое @@ -35,62 +99,4 @@ abstract class AbstractRepository implements RepositoryInterface { throw new RepositoryException($exception->getMessage()); } } - - - /** @inheritDoc */ - public function getAllProperties(object $class, callable $method = null) : array { - $properties = $this->initProperties($class); - return (isset($method)) ? array_map($method, $properties) : $properties; - } - - - /** @inheritDoc */ - public function getProperties(object $class, callable $method = null) : array { - $properties = $this->initProperties($class); - foreach ($properties as $fieldName => $value) { - if(isset($value)) $out[$fieldName] = $value; - } - return (isset($method)) ? array_map($method, $out ?? []) : $out ?? []; - } - - - /** - * @param object $class - * @return array - */ - private function initProperties(object $class): array { - $objectData = get_object_vars($class); - foreach ($objectData as $fieldName => $value) - { - // если есть внутренний метод (приоритетная обработка) - if(method_exists($class, 'get'.ucfirst($fieldName))) { - $fieldValue[$fieldName] = $class->{'get'.ucfirst($fieldName)}($value); - } - // если тип свойства класс (valueObject) - elseif($value instanceof ValueObjectInterface) { - $fieldValue[$fieldName] = $value->get(); - } - // если это логическое значение - elseif(is_bool($value)){ - $fieldValue[$fieldName] = (int) $value; - } - // если это дробное число - elseif(is_float($value)) { - $fieldValue[$fieldName] = $value; - } - // если это целое число - elseif(is_int($value)) { - $fieldValue[$fieldName] = $value; - } - // если это строка - elseif(is_string($value)) { - $fieldValue[$fieldName] = $value; - } - // to option_id - $fieldNameSnakeCase = strtolower(preg_replace("'([A-Z])'", "_$1", $fieldName)); - $out[$fieldNameSnakeCase] = $fieldValue[$fieldName] ?? null; - } - return $out ?? []; - } - } diff --git a/src/Mysql/MysqlRepositoryInterface.php b/src/Mysql/MysqlRepositoryInterface.php index 7e41ca9..6374fb1 100644 --- a/src/Mysql/MysqlRepositoryInterface.php +++ b/src/Mysql/MysqlRepositoryInterface.php @@ -33,35 +33,76 @@ interface MysqlRepositoryInterface extends RepositoryInterface { public function createListFromResult(string $class, bool|MysqlResultData $result, callable $function = null): array; /** - * @throws RepositoryException - */ - public function getEntityById(int $id, $require = false); - - /** - * @param EntityInterface $object + * @param int $id + * @param string|null $table * @return mixed * @throws RepositoryException */ - public function saveEntity(EntityInterface $object) : mixed; - - /** - * @param array $objects - * @return array - * @throws RepositoryException - */ - public function saveGroup(array $objects): array; + public function getEntityById(int $id, string $table = null): mixed; /** * @param EntityInterface $object + * @param string|null $table + * @return mixed + * @throws RepositoryException + */ + public function saveEntity(EntityInterface $object, string $table = null) : mixed; + + /** + * @param array $data + * @param string|null $table + * @param string $primaryKey + * @return mixed + * @throws RepositoryException + */ + public function saveData(array $data, string $table = null, string $primaryKey = 'id') : mixed; + + /** + * @param array $objects + * @param string|null $table + * @return array + * @throws RepositoryException + */ + public function saveEntityGroup(array $objects, string $table = null): array; + + /** + * @param array $objects + * @param string|null $table + * @param string $primaryKey + * @return array + * @throws RepositoryException + */ + public function saveDataGroup(array $objects, string $table = null, string $primaryKey = 'id'): array; + + /** + * @param EntityInterface $object + * @param string|null $table * @return bool * @throws RepositoryException */ - public function deleteEntity(EntityInterface $object) : bool; + public function deleteEntity(EntityInterface $object, string $table = null) : bool; /** * @return array */ public function getStorageLogs() : array; + /** + * @param string $table + * @return void + */ + public function setTable(string $table) : void; + + /** + * @param string $entity + * @return void + */ + public function setEntity(string $entity) : void; + + /** + * @param bool $debug + * @return void + */ + public function setDebug(bool $debug) : void; } diff --git a/src/RepositoryInterface.php b/src/RepositoryInterface.php index 2a956da..baf2da8 100644 --- a/src/RepositoryInterface.php +++ b/src/RepositoryInterface.php @@ -8,6 +8,7 @@ namespace Rmphp\Storage; +use ReflectionException; use Rmphp\Storage\Entity\EntityInterface; interface RepositoryInterface { @@ -22,18 +23,20 @@ interface RepositoryInterface { /** - * @param object $class - * @param callable|null $method - * @return array + * @param object $object + * @param array $data + * @return mixed + * @throws RepositoryException */ - public function getAllProperties(object $class, callable $method = null) : array; + public function updateFromData(object $object, array $data) : mixed; /** - * @param object $class + * @param object $object * @param callable|null $method * @return array + * @throws RepositoryException */ - public function getProperties(object $class, callable $method = null) : array; + public function getProperties(object $object, callable $method = null) : array; }