From 94ebb18b7e2e5c4d56132efc0f7f5df9b7a53122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=91=E6=9E=97?= Date: Mon, 10 Apr 2023 17:13:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=98=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ActiveQuery.php | 27 +- Base/AbstractCollection.php | 227 ++++++++------- Base/Model.php | 530 +++++++++--------------------------- Command.php | 52 ++-- Db.php | 56 ++-- Model.php | 120 ++++---- ModelInterface.php | 11 +- Pagination.php | 2 +- SqlBuilder.php | 67 ++--- Traits/Builder.php | 20 +- Traits/QueryTrait.php | 64 +---- 11 files changed, 409 insertions(+), 767 deletions(-) diff --git a/ActiveQuery.php b/ActiveQuery.php index 7a062e2..407f657 100644 --- a/ActiveQuery.php +++ b/ActiveQuery.php @@ -23,9 +23,6 @@ class ActiveQuery extends Component implements ISqlBuilder use QueryTrait; - /** @var array */ - public array $with = []; - /** @var bool */ public bool $asArray = FALSE; @@ -66,7 +63,6 @@ class ActiveQuery extends Component implements ISqlBuilder { $this->db = NULL; $this->useCache = FALSE; - $this->with = []; } /** @@ -134,14 +130,12 @@ class ActiveQuery extends Component implements ISqlBuilder } /** - * @param array $name + * @param array $methods * @return $this */ - public function with(array $name): static + public function with(array $methods): static { - foreach ($name as $val) { - $this->with[] = $val; - } + $this->modelClass->setWith($methods); return $this; } @@ -240,7 +234,6 @@ class ActiveQuery extends Component implements ISqlBuilder return new Collection($this, [], $this->modelClass); } - $this->getWith($this->modelClass); $collect = new Collection($this, $data, $this->modelClass); return $this->asArray ? $collect->toArray() : $collect; @@ -253,19 +246,10 @@ class ActiveQuery extends Component implements ISqlBuilder */ public function populate($data): ModelInterface { - return $this->getWith($this->modelClass::populate($data)); + return $this->modelClass::populate($data); } - /** - * @param ModelInterface $model - * @return ModelInterface - */ - public function getWith(ModelInterface $model): ModelInterface - { - return $model->setWith($this->with); - } - /** * @return int * @throws @@ -292,9 +276,6 @@ class ActiveQuery extends Component implements ISqlBuilder return $generate; } - var_dump($this->attributes, $generate[1]); - var_dump(array_merge($this->attributes, $generate[1])); - $generate[1] = array_merge($this->attributes, $generate[1]); return (bool)$this->execute(...$generate)->exec(); diff --git a/Base/AbstractCollection.php b/Base/AbstractCollection.php index 291be02..5576f68 100644 --- a/Base/AbstractCollection.php +++ b/Base/AbstractCollection.php @@ -27,20 +27,28 @@ use Traversable; abstract class AbstractCollection extends Component implements \IteratorAggregate, \ArrayAccess, ToArray { - /** - * @var ModelInterface[] - */ - protected array $_item = []; - - protected ModelInterface|string|null $model; - - protected ActiveQuery $query; + /** + * @var ModelInterface[] + */ + protected array $_item = []; - public function clean() - { - unset($this->query, $this->model, $this->_item); - } + /** + * @var ModelInterface|string|null + */ + protected ModelInterface|string|null $model; + + + /** + * @var ActiveQuery + */ + protected ActiveQuery $query; + + + public function clean() + { + unset($this->query, $this->model, $this->_item); + } /** @@ -51,112 +59,121 @@ abstract class AbstractCollection extends Component implements \IteratorAggregat * @param ModelInterface|null $model * @throws Exception */ - public function __construct($query, array $array = [], ModelInterface $model = null) - { - $this->_item = $array; - $this->query = $query; - $this->model = $model; + public function __construct($query, array $array = [], ModelInterface $model = null) + { + $this->_item = $array; + $this->query = $query; + $this->model = $model; - parent::__construct([]); - } + parent::__construct([]); + } - /** - * @return int - */ - #[Pure] public function getLength(): int - { - return count($this->_item); - } + /** + * @return int + */ + #[Pure] public function getLength(): int + { + return count($this->_item); + } - /** - * @param $item - */ - public function setItems($item) - { - $this->_item = $item; - } + /** + * @param $item + */ + public function setItems($item) + { + $this->_item = $item; + } - /** - * @param $model - */ - public function setModel($model) - { - $this->model = $model; - } + /** + * @param $model + */ + public function setModel($model) + { + $this->model = $model; + } - /** - * @param $item - */ - public function addItem($item) - { - $this->_item[] = $item; - } + /** + * @param $item + */ + public function addItem($item) + { + $this->_item[] = $item; + } - /** - * @return Traversable|CollectionIterator|ArrayIterator - * @throws Exception - */ - public function getIterator(): Traversable|CollectionIterator|ArrayIterator - { - return new CollectionIterator($this->model, $this->_item); - } + /** + * @return Traversable|CollectionIterator|ArrayIterator + * @throws Exception + */ + public function getIterator(): Traversable|CollectionIterator|ArrayIterator + { + return new CollectionIterator($this->model, $this->_item); + } - /** - * @return mixed - * @throws Exception - */ - public function getModel(): ModelInterface - { - return $this->model; - } + /** + * @return mixed + * @throws Exception + */ + public function getModel(): ModelInterface + { + return $this->model; + } - /** - * @param mixed $offset - * @return bool - */ - public function offsetExists(mixed $offset): bool - { - return !empty($this->_item) && isset($this->_item[$offset]); - } - - /** - * @param mixed $offset - * @return ModelInterface|null - * @throws Exception - */ - public function offsetGet(mixed $offset): ?ModelInterface - { - if (!$this->offsetExists($offset)) { - return NULL; - } - if (!($this->_item[$offset] instanceof ModelInterface)) { - return $this->model->populates($this->_item[$offset]); - } - return $this->_item[$offset]; - } - - /** - * @param mixed $offset - * @param mixed $value - */ - #[ReturnTypeWillChange] public function offsetSet(mixed $offset, mixed $value) - { - $this->_item[$offset] = $value; - } + /** + * @return ActiveQuery + */ + public function makeNewQuery(): ActiveQuery + { + return $this->model::query(); + } - /** - * @param mixed $offset - */ - #[ReturnTypeWillChange] public function offsetUnset(mixed $offset) - { - if ($this->offsetExists($offset)) { - unset($this->_item[$offset]); - } - } + /** + * @param mixed $offset + * @return bool + */ + public function offsetExists(mixed $offset): bool + { + return !empty($this->_item) && isset($this->_item[$offset]); + } + + /** + * @param mixed $offset + * @return ModelInterface|null + * @throws Exception + */ + public function offsetGet(mixed $offset): ?ModelInterface + { + if (!$this->offsetExists($offset)) { + return NULL; + } + if (!($this->_item[$offset] instanceof ModelInterface)) { + return $this->model->populates($this->_item[$offset]); + } + return $this->_item[$offset]; + } + + /** + * @param mixed $offset + * @param mixed $value + */ + #[ReturnTypeWillChange] public function offsetSet(mixed $offset, mixed $value) + { + $this->_item[$offset] = $value; + } + + + /** + * @param mixed $offset + */ + #[ReturnTypeWillChange] public function offsetUnset(mixed $offset) + { + if ($this->offsetExists($offset)) { + unset($this->_item[$offset]); + } + } } diff --git a/Base/Model.php b/Base/Model.php index b7f9f67..62391e1 100644 --- a/Base/Model.php +++ b/Base/Model.php @@ -46,28 +46,17 @@ use validator\Validator; abstract class Model extends Component implements ModelInterface, ArrayAccess, ToArray { - const GET = 'get'; - - - const SET = 'set'; - /** @var array */ protected array $_attributes = []; + /** @var array */ protected array $_oldAttributes = []; - /** @var array */ - protected array $_relate = []; /** @var null|string */ protected ?string $primary = NULL; - /** - * @var array - */ - private array $_annotations = []; - /** * @var bool @@ -76,15 +65,9 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T /** - * @var array + * @var bool */ - protected array $overwriteFields = []; - - - /** - * @var array - */ - protected array $actions = []; + protected bool $skipValidate = false; /** @@ -105,6 +88,18 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T protected array $_with = []; + /** + * @param array $config + * @throws Exception + */ + public function __construct(array $config = []) + { + parent::__construct($config); + + $this->init(); + } + + /** * @return array */ @@ -163,15 +158,6 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T } - /** - * @return array - */ - public function getActions(): array - { - return $this->actions; - } - - /** * @return bool */ @@ -209,31 +195,7 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T */ public function hasPrimary(): bool { - if ($this->primary !== NULL) { - return TRUE; - } - $primary = $this->getColumns()->getPrimaryKeys(); - if (!empty($primary)) { - return $this->primary = is_array($primary) ? current($primary) : $primary; - } - return FALSE; - } - - - /** - * @throws Exception - */ - public function isAutoIncrement(): bool - { - return $this->getAutoIncrement() !== NULL; - } - - /** - * @throws Exception - */ - public function getAutoIncrement(): int|string|null - { - return $this->getColumns()->getAutoIncrement(); + return $this->primary !== NULL && $this->primary !== ''; } /** @@ -256,7 +218,7 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T public function hasPrimaryValue(): bool { if ($this->hasPrimary()) { - return !empty($this->{$this->getPrimary()}); + return $this->getPrimaryValue() === null; } return false; } @@ -269,90 +231,23 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T public function getPrimaryValue(): ?int { if ($this->hasPrimary()) { - return $this->getAttribute($this->primary); + return $this->getAttribute($this->getPrimary()); } return null; } /** - * @param int|array|string|null $param + * @param array|string $param * @param null $db * @return Model|null - * @throws NotFindClassException - * @throws ReflectionException * @throws Exception */ - public static function findOne(int|array|string|null $param, $db = NULL): static|null + public static function findOne(array|string $param, $db = NULL): static|null { - if (is_null($param)) { - return NULL; - } - if (is_numeric($param)) { - $param = static::getPrimaryCondition($param); - } return static::query()->where($param)->first(); } - /** - * @param $param - * @return array - * @throws Exception - */ - private static function getPrimaryCondition($param): array - { - $primary = static::makeNewInstance()->getColumns()->getPrimaryKeys(); - if (empty($primary)) { - throw new Exception('Primary key cannot be empty.'); - } - if (is_array($primary)) { - $primary = current($primary); - } - return [$primary => $param]; - } - - - /** - * @param null $field - * @return ModelInterface|null - * @throws Exception - * @throws Exception - */ - public static function max($field = NULL): ?ModelInterface - { - $columns = static::makeNewInstance()->getColumns(); - if (empty($field)) { - $field = $columns->getFirstPrimary(); - } - $columns = $columns->get_fields(); - if (!isset($columns[$field])) { - return NULL; - } - $first = static::query()->max($field)->first(); - if (empty($first)) { - return NULL; - } - return $first[$field]; - } - - - /** - * @param string|int $param - * @return Model|null - * @throws NotFindClassException - * @throws ReflectionException - * @throws Exception - */ - public static function find(string|int $param): ?static - { - $columns = (new static())->getPrimary(); - if (empty($columns)) { - $columns = static::makeNewInstance()->getColumns()->getFirstPrimary(); - } - return static::query()->where([$columns => $param])->first(); - } - - /** * @return static */ @@ -375,10 +270,12 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T /** * @return ActiveQuery + * @throws Exception */ public static function query(): ActiveQuery { - return new ActiveQuery(new static()); + $model = new static(); + return (new ActiveQuery($model))->from($model->getTable())->alias('t1'); } @@ -396,11 +293,10 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T * @param null $condition * @param array $attributes * - * @param bool $if_condition_is_null * @return bool * @throws Exception */ - protected static function deleteByCondition($condition = NULL, array $attributes = [], bool $if_condition_is_null = FALSE): bool + protected static function deleteByCondition($condition = NULL, array $attributes = []): bool { $model = static::query(); if (!empty($condition)) { @@ -435,9 +331,8 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T */ public function setAttribute($name, $value): mixed { - $keys = Kiri::getDi()->get(Setter::class); - if ($keys->has(static::class, $name)) { - $method = $keys->get(static::class, $name); + $method = 'set' . ucfirst($name) . 'Attribute'; + if (method_exists($this, $method)) { $value = $this->{$method}($value); } return $this->_attributes[$name] = $value; @@ -451,8 +346,9 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T */ public function setOldAttribute($name, $value): mixed { - if (method_exists($this, 'set' . ucfirst($name) . 'Attribute')) { - $value = $this->{'set' . ucfirst($name) . 'Attribute'}($value); + $method = 'set' . ucfirst($name) . 'Attribute'; + if (method_exists($this, $method)) { + $value = $this->{$method}($value); } return $this->_oldAttributes[$name] = $value; } @@ -464,7 +360,7 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T */ public function setAttributes(array $param): static { - if (empty($param)) { + if (count($param) < 1) { return $this; } foreach ($param as $key => $attribute) { @@ -475,13 +371,13 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T /** - * @param $param + * @param array $param * @return $this * @throws ReflectionException */ - public function setOldAttributes($param): static + public function setOldAttributes(array $param): static { - if (empty($param) || !is_array($param)) { + if (count($param) < 1) { return $this; } foreach ($param as $key => $attribute) { @@ -492,105 +388,96 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T /** - * @param $attributes - * @param $param * @return $this|bool * @throws Exception */ - private function insert($param, $attributes): bool|static + private function insert(): bool|static { - [$sql, $param] = SqlBuilder::builder(static::query())->insert($param); + [$sql, $param] = SqlBuilder::builder(static::query())->insert($this->_attributes); + $dbConnection = $this->getConnection()->createCommand($sql, $param); $lastId = $dbConnection->save(); - if ($this->isAutoIncrement()) { - $lastId = $this->setPrimary((int)$lastId, $param); - } else { - $lastId = $this; + if ($lastId === false) { + return false; } - - $this->setIsNowExample(false); - - $this->refresh()->afterSave($attributes, $param); - - return $lastId; - } - - - /** - * @param $lastId - * @param $param - * @return static - * @throws Exception - */ - private function setPrimary($lastId, $param): static - { - if ($this->isAutoIncrement()) { - $this->setAttribute($this->getAutoIncrement(), (int)$lastId); - return $this; - } - - if (!$this->hasPrimary()) { - return $this; - } - - $primary = $this->getPrimary(); - if (empty($param[$primary])) { - $this->setAttribute($primary, (int)$lastId); + if ($this->hasPrimary()) { + $this->_attributes[$this->getPrimary()] = $lastId; } return $this; } /** - * @param $fields - * @param $condition - * @param $param + * @param array $old + * @param array|string $condition + * @param array $change * @return $this|bool * @throws Exception */ - private function updateInternal($fields, $condition, $param): bool|static + protected function updateInternal(array $old, array|string $condition, array $change): bool|static { - if (empty($param)) { - return TRUE; - } - if ($this->hasPrimary()) { - $condition = [$this->getPrimary() => $this->getPrimaryValue()]; - } - $query = static::query()->where($condition); - $generate = SqlBuilder::builder($query)->update($param); - if (is_bool($generate)) { - return $generate; + $generate = SqlBuilder::builder($query)->update($change); + if ($generate === false) { + return false; } - $generate[1] = array_merge($query->attributes, $generate[1]); - $command = $this->getConnection()->createCommand($generate[0], $generate[1]); + $command = $this->getConnection()->createCommand($generate, $query->attributes); if ($command->save()) { - return $this->refresh()->afterSave($fields, $param); + return $this->refresh()->afterSave($old, $change); + } else { + return FALSE; } - return FALSE; } /** - * @param null $data + * @param array $data * @return bool|$this * @throws Exception */ - public function save($data = NULL): static|bool + public function save(array $data = []): static|bool { - if (!is_null($data)) { - $this->_attributes = merge($this->_attributes, $data); + if (count($data) > 0) { + $this->_attributes = array_merge($this->_attributes, $data); } + if (!$this->isNewExample) { + if (!$this->validator($this->rules()) || !$this->beforeSave($this)) { + return FALSE; + } + + [$changes, $condition] = $this->diff(); + + return $this->updateInternal($condition, $condition, $changes); + } else { + return $this->create(); + } + } + + + /** + * @return array + */ + private function diff(): array + { + $changes = array_diff_assoc($this->_oldAttributes, $this->_attributes); + + $condition = array_intersect_key($this->_oldAttributes, $this->_attributes); + + return [$changes, $condition]; + } + + + /** + * @return $this|bool + * @throws Exception + */ + protected function create(): bool|static + { if (!$this->validator($this->rules()) || !$this->beforeSave($this)) { return FALSE; } - [$change, $condition, $fields] = $this->separation(); - if (!$this->getIsNowExample()) { - return $this->updateInternal($fields, $condition, $change); - } else { - return $this->insert($change, $fields); - } + return $this->insert(); } @@ -602,19 +489,21 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T { $this->_attributes = $value; $this->_oldAttributes = $value; - $this->setIsNowExample(FALSE); + $this->setIsNowExample(); return $this; } /** - * @param array|null $rule + * @param array $rule * @return bool * @throws Exception */ - public function validator(?array $rule): bool + public function validator(array $rule): bool { - if (empty($rule)) return TRUE; + if (count($rule) < 1 || $this->skipValidate) { + return TRUE; + } $validate = $this->resolve($rule); if (!$validate->validation()) { return $this->logger->addError($validate->getError(), 'mysql'); @@ -630,9 +519,7 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T */ private function resolve($rule): Validator { - $validate = Validator::getInstance(); - $validate->setParams($this->_attributes); - $validate->setModel($this); + $validate = Validator::instance($this->_attributes, $this); foreach ($rule as $val) { $field = array_shift($val); @@ -652,97 +539,6 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T } - /** - * @param string $name - * @param mixed $value - * @param string $type - * @return mixed - */ - protected function runAnnotation(string $name, mixed $value, string $type = self::GET): mixed - { - return call_user_func($this->_annotations[$type][$name], $value); - } - - - /** - * @return array - * @throws Exception - */ - private function separation(): array - { - $assoc = array_diff_assoc($this->_attributes, $this->_oldAttributes); - - $column = $this->getColumns(); - - $uassoc = array_intersect_assoc($this->_attributes, $this->_oldAttributes); - foreach ($assoc as $key => $item) { - $encode = $column->get_fields($key); - if ($column->isString($encode) && $item === null) { - unset($assoc[$key]); - } - } - return [$assoc, $uassoc, array_keys($assoc)]; - } - - - /** - * @param $columns - * @param $format - * @param $key - * @param $value - * @return mixed - */ - public function toFormat($columns, $format, $key, $value): mixed - { - if (isset($format[$key])) { - return $columns->encode($value, $columns->clean($format[$key])); - } - return $value; - } - - - /** - * @param $name - * @param $value - */ - public function setRelate($name, $value) - { - $this->_relate[$name] = $value; - } - - - /** - * @param $name - * @return bool - */ - public function hasRelate($name): bool - { - return isset($this->_relate[$name]); - } - - - /** - * @param array $relates - */ - public function setRelates(array $relates) - { - if (empty($relates)) { - return; - } - foreach ($relates as $key => $val) { - $this->setRelate($key, $val); - } - } - - /** - * @return array - */ - public function getRelates(): array - { - return $this->_relate; - } - - /** * @return Relation|null */ @@ -759,7 +555,7 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T */ public function has($attribute): bool { - return static::makeNewInstance()->getColumns()->hasField($attribute); + return true; } /**ƒ @@ -783,22 +579,22 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T /** - * @param $attributes + * @param $oldAttributes * @param $changeAttributes * @return bool - * @throws Exception */ - public function afterSave($attributes, $changeAttributes): bool + public function afterSave($oldAttributes, $changeAttributes): bool { return TRUE; } /** - * @param $model + * @param self $model * @return bool + * @throws Exception */ - public function beforeSave($model): bool + public function beforeSave(self $model): bool { return TRUE; } @@ -820,13 +616,14 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T */ public function __set($name, $value): void { - $method = 'set' . ucfirst($name); - if (method_exists($this, $method)) { - $this->{$method}($value); + if ($this->hasRelateMethod($name, 'set')) { + $this->{'set' . ucfirst($name)}($value); } else { - $overrideSetter = Kiri::getDi()->get(Setter::class); - - $this->_attributes[$name] = $overrideSetter->override($this, $name, $value); + $method = 'set' . ucfirst($name) . 'Attribute'; + if (method_exists($this, $method)) { + $value = $this->{$method} ($value); + } + $this->_attributes[$name] = $value; } } @@ -838,10 +635,11 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T */ public function __get($name): mixed { - if (isset($this->_attributes[$name])) { - return $this->withPropertyOverride($name); + $value = $this->_attributes[$name] ?? null; + if (!$this->hasRelateMethod($name)) { + return $this->withPropertyOverride($name, $value); } else { - return $this->getRelateValue($name); + return $this->withRelate($name); } } @@ -854,23 +652,23 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T */ protected function withPropertyOverride($name, $value = null): mixed { - if (is_null($value)) { - $value = $this->_attributes[$name] ?? NULL; + $method = 'get' . ucfirst($name) . 'Attribute'; + if (method_exists($this, $method)) { + return $this->{$method}($value); + } else { + return $value; } - - $overrideGetter = Kiri::getDi()->get(Getter::class); - - return $overrideGetter->override($this, $name, $value); } /** - * @param $name + * @param string $name + * @param string $prefix * @return bool */ - protected function hasRelateMethod($name): bool + protected function hasRelateMethod(string $name, string $prefix = 'get'): bool { - return method_exists($this, 'get' . ucfirst($name)); + return method_exists($this, $prefix . ucfirst($name)); } @@ -878,25 +676,8 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T * @param $name * @return mixed|null */ - protected function withRelate($name): mixed + private function withRelate($name): mixed { - $response = $this->getRelateValue($name); - if ($response instanceof ToArray) { - $response = $response->toArray(); - } - return $response; - } - - - /** - * @param $name - * @return mixed - */ - protected function getRelateValue($name): mixed - { - if (!$this->hasRelateMethod($name)) { - return null; - } $response = $this->{'get' . ucfirst($name)}(); if ($response instanceof HasBase) { $response = $response->get(); @@ -905,42 +686,6 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T } - /** - * @param $name - * @param $value - * @return mixed - * @throws Exception - */ - protected function _decode($name, $value): mixed - { - return $this->getColumns()->_decode($name, $value); - } - - - /** - * @param $name - * @return mixed - */ - private function with($name): mixed - { - $data = $this->{$this->_relate[$name]}(); - if ($data instanceof HasBase) { - return $data->get(); - } - return $data; - } - - - /** - * @param $item - * @param $data - * @return array - */ - protected function resolveAttributes($item, $data): array - { - return call_user_func($item, $data); - } - /** * @param $name * @return bool @@ -993,9 +738,6 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T } unset($this->_attributes[$offset]); unset($this->_oldAttributes[$offset]); - if (isset($this->_relate)) { - unset($this->_relate[$offset]); - } } /** @@ -1018,6 +760,7 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T ->table($this->getTable()); } + /** * @param array $data * @return static @@ -1025,33 +768,12 @@ abstract class Model extends Component implements ModelInterface, ArrayAccess, T */ public static function populate(array $data): static { - $model = instance(static::class); + $model = new static(); $model->_attributes = $data; $model->_oldAttributes = $data; - $model->setIsNowExample(FALSE); + $model->setIsNowExample(); return $model; } - - - /** - * @return void - */ - public function __clone(): void - { - } - - - /** - * @param $method - * @param $value - * @return Closure - */ - protected function dispatcher($method, $value): Closure - { - return function () use ($method, $value) { - return $this->{$method}($value); - }; - } /** diff --git a/Command.php b/Command.php index d6a59bb..5584c23 100644 --- a/Command.php +++ b/Command.php @@ -28,19 +28,19 @@ class Command extends Component const FETCH_ALL = 'fetchAll'; const EXECUTE = 'execute'; const FETCH_COLUMN = 'fetchColumn'; - + const DB_ERROR_MESSAGE = 'The system is busy, please try again later.'; - + /** @var Connection */ public Connection $connection; - + /** @var ?string */ public ?string $sql = ''; - + /** @var array */ public array $params = []; - - + + /** * @return int|bool * @throws Exception @@ -49,7 +49,7 @@ class Command extends Component { return $this->_execute(); } - + /** * @return int|bool * @throws Exception @@ -58,13 +58,13 @@ class Command extends Component { return $this->_execute(); } - - + + /** - * @return bool|array|null + * @return bool|array * @throws Exception */ - public function all(): null|bool|array + public function all(): bool|array { try { $client = $this->connection->getConnection(); @@ -82,7 +82,7 @@ class Command extends Component $this->connection->release($client ?? null); } } - + /** * @return bool|array|null * @throws Exception @@ -105,7 +105,7 @@ class Command extends Component $this->connection->release($client ?? null); } } - + /** * @return bool|array|null * @throws Exception @@ -128,7 +128,7 @@ class Command extends Component $this->connection->release($client ?? null); } } - + /** * @return int|bool * @throws Exception @@ -151,8 +151,8 @@ class Command extends Component $this->connection->release($client ?? null); } } - - + + /** * @return int|bool * @throws Exception @@ -161,7 +161,7 @@ class Command extends Component { return $this->_execute(); } - + /** * @return bool|int * @throws ConfigException @@ -179,7 +179,7 @@ class Command extends Component } $result = $client->lastInsertId(); $prepare->closeCursor(); - + if (!$client->inTransaction()) { $this->connection->release($client); } @@ -191,8 +191,8 @@ class Command extends Component return $this->error($throwable); } } - - + + /** * @param \Throwable $throwable * @return bool @@ -202,8 +202,8 @@ class Command extends Component $message = $this->sql . '.' . json_encode($this->params, JSON_UNESCAPED_UNICODE); return $this->logger->addError($message . $throwable->getMessage(), 'mysql'); } - - + + /** * @return int|bool * @throws Exception @@ -212,7 +212,7 @@ class Command extends Component { return $this->_execute(); } - + /** * @return int|bool * @throws Exception @@ -221,7 +221,7 @@ class Command extends Component { return $this->_execute(); } - + /** * @param array $data * @return $this @@ -233,7 +233,7 @@ class Command extends Component } return $this; } - + /** * @param $sql * @return $this @@ -244,5 +244,5 @@ class Command extends Component $this->sql = $sql; return $this; } - + } diff --git a/Db.php b/Db.php index f25af03..ea60e5a 100644 --- a/Db.php +++ b/Db.php @@ -9,6 +9,7 @@ declare(strict_types=1); namespace Database; +use Closure; use Database\Affair\Commit; use Database\Affair\Rollback; use Database\Traits\QueryTrait; @@ -50,10 +51,35 @@ class Db implements ISqlBuilder } + /** + * @param Closure $closure + * @param mixed ...$params + * @return mixed + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws Exception + */ + public static function Transaction(Closure $closure, ...$params): mixed + { + static::beginTransaction(); + try { + $result = call_user_func($closure, ...$params); + } catch (\Throwable $throwable) { + $result = logger()->addError($throwable->getMessage(), 'mysql'); + } finally { + if ($result === false) { + static::rollback(); + } else { + static::commit(); + } + return $result; + } + } + + /** * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface - * @throws ReflectionException */ public static function commit(): void { @@ -67,7 +93,6 @@ class Db implements ISqlBuilder * @return void * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface - * @throws ReflectionException */ public static function rollback(): void { @@ -290,11 +315,11 @@ class Db implements ISqlBuilder /** * @param string $table * @param Connection|NULL $connection - * @return mixed + * @return array|bool|null * @throws ConfigException * @throws Exception */ - public static function showCreateSql(string $table, Connection $connection = NULL): mixed + public static function showCreateSql(string $table, Connection $connection = NULL): array|bool|null { $connection = static::getDefaultConnection($connection); @@ -305,11 +330,11 @@ class Db implements ISqlBuilder /** * @param string $table * @param Connection|NULL $connection - * @return mixed + * @return array|bool|null * @throws ConfigException * @throws Exception */ - public static function desc(string $table, Connection $connection = NULL): mixed + public static function desc(string $table, Connection $connection = NULL): array|bool { $connection = static::getDefaultConnection($connection); @@ -321,12 +346,12 @@ class Db implements ISqlBuilder /** * @param string $table * @param Connection|NULL $connection - * @return mixed + * @return array|bool|null * @throws Exception */ - public static function show(string $table, Connection $connection = NULL): mixed + public static function show(string $table, Connection $connection = NULL): array|bool|null { - if (empty($table)) { + if ($table == '') { return null; } $connection = static::getDefaultConnection($connection); @@ -342,12 +367,11 @@ class Db implements ISqlBuilder /** * @param null|Connection $connection - * @param null $name + * @param string $name * @return mixed - * @throws ConfigException * @throws Exception */ - public static function getDefaultConnection(?Connection $connection, $name = null): Connection + public static function getDefaultConnection(?Connection $connection, string $name = 'db'): Connection { if ($connection instanceof Connection) { return $connection; @@ -356,13 +380,7 @@ class Db implements ISqlBuilder if (empty($databases) || !is_array($databases)) { throw new Exception('Please configure the database link.'); } - if (!empty($name)) { - if (!isset($databases[$name])) { - throw new Exception('Please configure the database link.'); - } - return $databases[$name]; - } - return current($databases); + return \Kiri::service()->get($databases[$name]); } diff --git a/Model.php b/Model.php index 3ba92e1..e82a84f 100644 --- a/Model.php +++ b/Model.php @@ -15,6 +15,8 @@ use Exception; use Kiri; use Kiri\Exception\NotFindClassException; use Kiri\Error\StdoutLoggerInterface; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; use ReflectionException; defined('SAVE_FAIL') or define('SAVE_FAIL', 3227); @@ -99,31 +101,20 @@ class Model extends Base\Model /** * @param array $condition * @param array $attributes - * @return bool|ModelInterface - * @throws ReflectionException - * @throws NotFindClassException - * @throws Exception + * @return bool|static + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface */ public static function findOrCreate(array $condition, array $attributes): bool|static { - $logger = Kiri::getDi()->get(StdoutLoggerInterface::class); - if (empty($attributes)) { - return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql'); - } - - /** @var static $select */ - $select = static::query()->where($condition)->first(); - if (!empty($select)) { + return Db::Transaction(function ($condition, $attributes) { + /** @var static $select */ + $select = static::query()->where($condition)->first(); + if ($select === null) { + $select = static::populate(array_merge($condition, $attributes))->create(); + } return $select; - } - - $select = new static(); - $select->setAttributes($condition); - $select->setAttributes($attributes); - if (!$select->save()) { - throw new Exception($select->getLastError()); - } - return $select; + }, $condition, $attributes); } @@ -131,25 +122,19 @@ class Model extends Base\Model * @param array $condition * @param array $attributes * @return bool|static - * @throws Exception + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface */ public static function createOrUpdate(array $condition, array $attributes = []): bool|static { - $logger = Kiri::getDi()->get(StdoutLoggerInterface::class); - if (empty($attributes)) { - return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql'); - } - /** @var static $select */ - $select = static::query()->where($condition)->first(); - if (empty($select)) { - $select = new static(); - $select->setAttributes($condition); - } - $select->setAttributes($attributes); - if (!$select->save()) { - throw new Exception($select->getLastError()); - } - return $select; + return Db::Transaction(function ($condition, $attributes) { + /** @var static $select */ + $select = static::query()->where($condition)->first(); + if (empty($select)) { + $select = static::populate($condition); + } + return $select->save($attributes); + }, $condition, $attributes); } @@ -168,18 +153,26 @@ class Model extends Base\Model if (is_bool($create)) { return false; } - return $this->getConnection()->createCommand($create[0], $create[1])->exec(); + return $this->getConnection()->createCommand($create, $activeQuery->attributes)->exec(); } /** - * @param array $fields + * @param array $params * @return ModelInterface|bool * @throws Exception */ - public function update(array $fields): static|bool + public function update(array $params): static|bool { - return $this->save($fields); + if (!$this->validator($this->rules()) || !$this->beforeSave($this)) { + return FALSE; + } + + $condition = array_diff_assoc($this->_oldAttributes, $params); + + $old = array_intersect_key($this->_oldAttributes, $params); + + return $this->updateInternal($old, $condition, $params); } @@ -202,18 +195,13 @@ class Model extends Base\Model */ public function delete(): bool { - $primary = $this->getPrimary(); - if (empty($primary) || !$this->hasPrimaryValue()) { - return $this->logger->addError("Only primary key operations are supported.", 'mysql'); - } - if (!$this->beforeDelete()) { + if ($this->beforeDelete()) { + $result = static::deleteByCondition($this->_attributes); + + return $this->afterDelete($result); + } else { return false; } - $result = static::deleteByCondition([$primary => $this->getPrimaryValue()]); - - $this->afterDelete($result); - - return $result; } @@ -265,24 +253,23 @@ class Model extends Base\Model public function toArray(): array { $data = $this->_attributes; - foreach ($this->overwriteFields as $key => $datum) { + foreach ($data as $key => $datum) { $method = 'get' . ucfirst($key) . 'Attribute'; + if (!method_exists($this, $method)) { + continue; + } $data[$key] = $this->{$method}($datum); } - return $this->withRelates($data); - } - /** - * @param $relates - * @return array - * @throws Exception - */ - private function withRelates($relates): array - { - foreach ($this->_with as $val) { - $relates[$val] = $this->withRelate($val); + $with = $this->getWith(); + foreach ($with as $value) { + $join = $this->{'get' . ucfirst($value)}(); + if ($join instanceof Kiri\ToArray) { + $join = $join->toArray(); + } + $data[$value] = $join; } - return $relates; + return $data; } @@ -372,10 +359,11 @@ class Model extends Base\Model /** * @param bool $result - * @return void + * @return bool */ - public function afterDelete(bool $result): void + public function afterDelete(bool $result): bool { + return $result; } /** diff --git a/ModelInterface.php b/ModelInterface.php index 1e47a3e..88d5df2 100644 --- a/ModelInterface.php +++ b/ModelInterface.php @@ -18,18 +18,11 @@ interface ModelInterface { /** - * @param int|array|string|null $param + * @param array|string $param * @param null $db * @return ModelInterface */ - public static function findOne(int|array|string|null $param, $db = NULL): mixed; - - - /** - * @param string|int $param - * @return ModelInterface - */ - public static function find(string|int $param): mixed; + public static function findOne(array|string $param, $db = NULL): mixed; /** diff --git a/Pagination.php b/Pagination.php index cddfa3b..4908e2b 100644 --- a/Pagination.php +++ b/Pagination.php @@ -128,7 +128,7 @@ class Pagination extends Component * @return void * @throws Exception */ - public function plunk(array $param = []) + public function plunk(array $param = []): void { $this->loop($param); } diff --git a/SqlBuilder.php b/SqlBuilder.php index e483335..0bc440a 100644 --- a/SqlBuilder.php +++ b/SqlBuilder.php @@ -60,11 +60,9 @@ class SqlBuilder extends Component * @return bool|array * @throws Exception */ - public function update(array $attributes): bool|array + public function update(array $attributes): bool|string { - [$string, $array] = $this->builderParams($attributes); - - return $this->__updateBuilder($string, $array); + return $this->__updateBuilder($this->builderParams($attributes)); } @@ -74,31 +72,28 @@ class SqlBuilder extends Component * @return bool|array * @throws Exception */ - public function mathematics(array $attributes, string $opera = '+'): bool|array + public function mathematics(array $attributes, string $opera = '+'): bool|string { $string = []; foreach ($attributes as $attribute => $value) { $string[] = $attribute . '=' . $attribute . $opera . $value; } - return $this->__updateBuilder($string, []); + return $this->__updateBuilder($string); } /** * @param array $string - * @param array $params - * @return array|bool + * @return string|bool * @throws Exception */ - private function __updateBuilder(array $string, array $params): array|bool + private function __updateBuilder(array $string): string|bool { if (empty($string)) { return $this->logger->addError('None data update.'); } - $update = 'UPDATE ' . $this->tableName() . ' SET ' . implode(',', $string) . $this->_prefix(); - - return [$update, $params]; + return 'UPDATE ' . $this->query->from . ' SET ' . implode(',', $string) . $this->_prefix(); } @@ -110,7 +105,7 @@ class SqlBuilder extends Component */ public function insert(array $attributes, bool $isBatch = false): array { - $update = 'INSERT INTO ' . $this->tableName(); + $update = 'INSERT INTO ' . $this->query->from; if ($isBatch === false) { $attributes = [$attributes]; } @@ -119,7 +114,7 @@ class SqlBuilder extends Component $order = 0; $keys = $params = []; foreach ($attributes as $attribute) { - [$_keys, $params] = $this->builderParams($attribute, true, $params, $order); + $_keys = $this->builderParams($attribute, true, $order); $keys[] = implode(',', $_keys); $order++; @@ -134,7 +129,7 @@ class SqlBuilder extends Component */ public function delete(): string { - return 'DELETE FROM ' . $this->tableName() . ' WHERE ' . $this->_prefix(); + return 'DELETE FROM ' . $this->query->from . ' WHERE ' . $this->_prefix(); } @@ -151,23 +146,22 @@ class SqlBuilder extends Component /** * @param array $attributes * @param bool $isInsert - * @param array $params * @param int $order * @return array[] * a=:b, */ - #[Pure] private function builderParams(array $attributes, bool $isInsert = false, array $params = [], int $order = 0): array + private function builderParams(array $attributes, bool $isInsert = false, int $order = 0): array { $keys = []; foreach ($attributes as $key => $value) { if ($isInsert === true) { $keys[] = ':save' . $key . $order; - $params[':save' . $key . $order] = $value; + $this->query->bindParam(':save' . $key . $order, $value); } else { - [$keys, $params] = $this->resolveParams($key, $value, $order, $params, $keys); + $keys = $this->resolveParams($key, $value, $order, $keys); } } - return [$keys, $params]; + return $keys; } @@ -175,14 +169,13 @@ class SqlBuilder extends Component * @param string $key * @param mixed $value * @param int $order - * @param array $params * @param array $keys * @return array */ - private function resolveParams(string $key, mixed $value, int $order, array $params, array $keys): array + private function resolveParams(string $key, mixed $value, int $order, array $keys): array { if (is_null($value)) { - return [$keys, $params]; + return $keys; } if ( str_starts_with($value, '+ ') || @@ -190,10 +183,10 @@ class SqlBuilder extends Component ) { $keys[] = $key . '=' . $key . ' ' . $value; } else { - $params[':update' . $key . $order] = $value; + $this->query->bindParam(':update' . $key . $order, $value); $keys[] = $key . '=:update' . $key . $order; } - return [$keys, $params]; + return $keys; } @@ -266,7 +259,7 @@ class SqlBuilder extends Component if (count($this->query->select) < 1) { $this->query->select = ['*']; } - $select = "SELECT " . implode(',', $this->query->select) . " FROM " . $this->tableName(); + $select = "SELECT " . implode(',', $this->query->select) . " FROM " . $this->query->from; if ($this->query->alias != "") { $select .= " AS " . $this->query->alias; } @@ -297,7 +290,7 @@ class SqlBuilder extends Component */ public function truncate(): string { - return sprintf('TRUNCATE %s', $this->tableName()); + return sprintf('TRUNCATE %s', $this->query->from); } @@ -310,24 +303,4 @@ class SqlBuilder extends Component return $this->where($this->query->where); } - - /** - * @return string - * @throws Exception - */ - public function tableName(): string - { - if ($this->query->from === null) { - return $this->query->modelClass->getTable(); - } - if ($this->query->from instanceof \Closure) { - return $this->query->from = '(' . $this->query->makeClosureFunction($this->query->from) . ')'; - } - if ($this->query->from instanceof ActiveQuery) { - return $this->query->from = '(' . SqlBuilder::builder($this->query->from)->get($this->query->from) . ')'; - } else { - return $this->query->from; - } - } - } diff --git a/Traits/Builder.php b/Traits/Builder.php index f26a49f..5797f0a 100644 --- a/Traits/Builder.php +++ b/Traits/Builder.php @@ -70,12 +70,12 @@ trait Builder /** - * @param $group + * @param string $group * @return string */ - private function builderGroup($group): string + private function builderGroup(string $group): string { - if (empty($group)) { + if ($group != '') { return ''; } return ' GROUP BY ' . $group; @@ -143,7 +143,8 @@ trait Builder private function resolveCondition($field, $condition, $_tmp): string { if (is_string($field)) { - return $field . ' = \'' . $condition . '\''; + $this->query->bindParam(':where' . $field, $condition); + return $field . ' = ' . ':where' . $field; } else if (is_string($condition)) { return $condition; } else { @@ -192,9 +193,6 @@ trait Builder } - public array $params = []; - - /** * @param $condition * @return array @@ -203,12 +201,8 @@ trait Builder { $_array = []; foreach ($condition as $key => $value) { - if (!is_numeric($key)) { - $this->query->bindParam(':' . $key, $value); - $_array[] = $key . '=:' . $key; - } else { - $_array[] = $value; - } + $this->query->bindParam(':hash' . $key, $value); + $_array[] = $key . '=:hash' . $key; } return $_array; } diff --git a/Traits/QueryTrait.php b/Traits/QueryTrait.php index 4b6394a..fd77524 100644 --- a/Traits/QueryTrait.php +++ b/Traits/QueryTrait.php @@ -34,7 +34,7 @@ trait QueryTrait public int $offset = 0; public int $limit = 500; public string $group = ''; - public string|Closure|ActiveQuery|null $from = null; + public string $from = ''; public string $alias = 't1'; public array $filter = []; @@ -103,7 +103,7 @@ trait QueryTrait */ public function whereRaw(string $whereRaw): static { - if (empty($whereRaw)) { + if ($whereRaw == '') { return $this; } $this->where[] = $whereRaw; @@ -112,36 +112,10 @@ trait QueryTrait /** - * @param string|array|Closure $condition - * @param string|array|Closure $condition1 - * @param string|array|Closure $condition2 - * @return $this - * @throws - */ - public function whereIf(string|array|Closure $condition, string|array|Closure $condition1, string|array|Closure $condition2): static - { - if (!is_string($condition)) { - $condition = $this->makeClosureFunction($condition); - } - - if (!is_string($condition1)) { - $condition1 = $this->makeClosureFunction($condition1); - } - - if (!is_string($condition2)) { - $condition2 = $this->makeClosureFunction($condition2); - } - - $this->where[] = 'IF(' . $condition . ', ' . $condition1 . ', ' . $condition2 . ')'; - return $this; - } - - - /** - * @param $bool + * @param bool $bool * @return $this */ - public function ifNotWhere($bool): static + public function ifNotWhere(bool $bool): static { $this->ifNotWhere = $bool; return $this; @@ -210,27 +184,6 @@ trait QueryTrait return $this; } - /** - * @param array|Closure|string $columns - * @return $this - */ - public function filter(array|Closure|string $columns): static - { - if (!$columns) { - return $this; - } - if (is_callable($columns, TRUE)) { - return call_user_func($columns, $this); - } - if (is_string($columns)) { - $columns = explode(',', $columns); - } - if (!is_array($columns)) { - return $this; - } - $this->filter = $columns; - return $this; - } /** * @param string $alias @@ -252,6 +205,9 @@ trait QueryTrait */ public function from(string|Closure $tableName): static { + if ($tableName instanceof Closure) { + $tableName = call_user_func($tableName, $this->makeNewSqlGenerate()); + } $this->from = $tableName; return $this; } @@ -325,7 +281,7 @@ trait QueryTrait } $tableName = $model->getTable(); } - return $this->join(...["LEFT JOIN " . $tableName, $alias, $onCondition, $param]); + return $this->join("LEFT JOIN " . $tableName, $alias, $onCondition, $param); } /** @@ -345,7 +301,7 @@ trait QueryTrait } $tableName = $model->getTable(); } - return $this->join(...["RIGHT JOIN " . $tableName, $alias, $onCondition, $param]); + return $this->join("RIGHT JOIN " . $tableName, $alias, $onCondition, $param); } /** @@ -365,7 +321,7 @@ trait QueryTrait } $tableName = $model->getTable(); } - return $this->join(...["INNER JOIN " . $tableName, $alias, $onCondition, $param]); + return $this->join("INNER JOIN " . $tableName, $alias, $onCondition, $param); } /**