diff --git a/.gitignore b/.gitignore index efca283..2ea4619 100644 --- a/.gitignore +++ b/.gitignore @@ -1,34 +1,34 @@ -# Created by .ignore support plugin (hsz.mobi) -### Yii template -assets/* -!assets/.gitignore -protected/runtime/* -!protected/runtime/.gitignore -protected/data/*.db -themes/classic/views/ - -### Example user template template -### Example user template - -# IntelliJ project files -.idea -*.iml -out -gen - -composer.lock - -*.log -commands/result -config/setting.php -tests/ -vendor/ -runtime/ - -*.xml -*.lock - -oot -d - -composer.lock +# Created by .ignore support plugin (hsz.mobi) +### Yii template +assets/* +!assets/.gitignore +protected/runtime/* +!protected/runtime/.gitignore +protected/data/*.db +themes/classic/views/ + +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen + +composer.lock + +*.log +commands/result +config/setting.php +tests/ +vendor/ +runtime/ + +*.xml +*.lock + +oot +d + +composer.lock diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php index 567fa45..c873bb7 100644 --- a/.phpstorm.meta.php +++ b/.phpstorm.meta.php @@ -1,18 +1,18 @@ -modelClass = $model; - - $this->builder = SqlBuilder::builder($this); - parent::__construct($config); - } - - - /** - * 清除不完整数据 - */ - public function clear() - { - $this->db = NULL; - $this->useCache = FALSE; - $this->with = []; - } - - /** - * @param $key - * @param $value - * @return $this - */ - public function addParam($key, $value): static - { - $this->attributes[$key] = $value; - return $this; - } - - - /** - * @param int $size - * @param int $page - * @return array - * @throws Exception - */ - #[ArrayShape(['code' => "int", 'message' => "string", 'size' => "mixed", 'page' => "mixed", 'count' => "int", 'next' => "mixed", 'prev' => "mixed", 'param' => "array"])] - public function pagination(int $size = 20, int $page = 1): array - { - $page = max(1, $page); - $size = max(1, $size); - - $offset = ($page - 1) * $size; - - $count = $this->count(); - $lists = $this->limit($offset, $size)->get()->toArray(); - return [ - 'code' => 0, - 'message' => 'ok', - 'size' => $size, - 'page' => $page, - 'count' => $count, - 'next' => max($page + 1, 1), - 'prev' => max($page - 1, 1), - 'param' => $lists, - ]; - } - - - /** - * @param array $values - * @return $this - */ - public function addParams(array $values): static - { - foreach ($values as $key => $val) { - $this->addParam($key, $val); - } - return $this; - } - - /** - * @param $name - * @return $this - */ - public function with($name): static - { - if (empty($name)) { - return $this; - } - if (is_string($name)) { - $name = explode(',', $name); - } - foreach ($name as $val) { - array_push($this->with, $val); - } - return $this; - } - - - /** - * @param $sql - * @param array $params - * @return mixed - * @throws Exception - */ - public function execute($sql, array $params = []): Command - { - return $this->modelClass->getConnection()->createCommand($sql, $params); - } - - - /** - * @return ModelInterface|null - * @throws Exception - */ - public function first(): ModelInterface|null - { - $data = $this->execute($this->builder->one())->one(); - if (empty($data)) { - return NULL; - } - return $this->populate($data); - } - - - /** - * @return string - * @throws Exception - */ - public function toSql(): string - { - return $this->builder->get(); - } - - - /** - * @return array|Collection - */ - public function get(): Collection|array - { - return $this->all(); - } - - - /** - * @throws Exception - */ - public function flush(): array|bool|int|string|null - { - return $this->execute($this->builder->truncate())->exec(); - } - - - /** - * @param int $size - * @param callable $callback - * @return Pagination - * @throws Exception - */ - public function page(int $size, callable $callback): Pagination - { - $pagination = new Pagination($this); - $pagination->setOffset(0); - $pagination->setLimit($size); - $pagination->setCallback($callback); - return $pagination; - } - - /** - * @param string $field - * @param string $setKey - * - * @return array|null - * @throws Exception - */ - public function column(string $field, string $setKey = ''): ?array - { - return $this->all()->column($field, $setKey); - } - - /** - * @return array|Collection - * @throws - */ - public function all(): Collection|array - { - $data = $this->execute($this->builder->all())->all(); - if (!empty($this->with)) { - $this->getWith($this->modelClass); - } - $collect = new Collection($this, $data, $this->modelClass); - if ($this->asArray) { - return $collect->toArray(); - } - return $collect; - } - - /** - * @param $data - * @return ModelInterface - * @throws Exception - */ - public function populate($data): ModelInterface - { - return $this->getWith($this->modelClass::populate($data)); - } - - - /** - * @param ModelInterface $model - * @return ModelInterface - */ - public function getWith(ModelInterface $model): ModelInterface - { - if (empty($this->with) || !is_array($this->with)) { - return $model; - } - return $model->setWith($this->with); - } - - /** - * @return int - * @throws Exception - */ - public function count(): int - { - $data = $this->execute($this->builder->count())->one(); - if ($data && is_array($data)) { - return (int)array_shift($data); - } - return 0; - } - - - /** - * @param array $data - * @return array|Command|bool|int|string - * @throws Exception - */ - public function batchUpdate(array $data): Command|array|bool|int|string - { - $generate = $this->builder->update($data); - if (is_bool($generate)) { - return $generate; - } - return $this->execute(...$generate)->exec(); - } - - /** - * @param array $data - * @return bool - * @throws Exception - */ - public function batchInsert(array $data): bool - { - [$sql, $params] = $this->builder->insert($data, TRUE); - - - return $this->execute($sql, $params)->exec(); - } - - /** - * @param $filed - * - * @return null - * @throws Exception - */ - public function value($filed) - { - return $this->first()[$filed] ?? NULL; - } - - /** - * @return bool - * @throws Exception - */ - public function exists(): bool - { - return !empty($this->execute($this->builder->one())->fetchColumn()); - } - - - /** - * @param bool $getSql - * @return int|bool|string|null - * @throws Exception - */ - public function delete(bool $getSql = FALSE): int|bool|string|null - { - $sql = $this->builder->delete(); - if ($getSql === FALSE) { - return $this->execute($sql)->delete(); - } - return $sql; - } -} +modelClass = $model; + + $this->builder = SqlBuilder::builder($this); + parent::__construct($config); + } + + + /** + * 清除不完整数据 + */ + public function clear() + { + $this->db = NULL; + $this->useCache = FALSE; + $this->with = []; + } + + /** + * @param $key + * @param $value + * @return $this + */ + public function addParam($key, $value): static + { + $this->attributes[$key] = $value; + return $this; + } + + + /** + * @param int $size + * @param int $page + * @return array + * @throws Exception + */ + #[ArrayShape(['code' => "int", 'message' => "string", 'size' => "mixed", 'page' => "mixed", 'count' => "int", 'next' => "mixed", 'prev' => "mixed", 'param' => "array"])] + public function pagination(int $size = 20, int $page = 1): array + { + $page = max(1, $page); + $size = max(1, $size); + + $offset = ($page - 1) * $size; + + $count = $this->count(); + $lists = $this->limit($offset, $size)->get()->toArray(); + return [ + 'code' => 0, + 'message' => 'ok', + 'size' => $size, + 'page' => $page, + 'count' => $count, + 'next' => max($page + 1, 1), + 'prev' => max($page - 1, 1), + 'param' => $lists, + ]; + } + + + /** + * @param array $values + * @return $this + */ + public function addParams(array $values): static + { + foreach ($values as $key => $val) { + $this->addParam($key, $val); + } + return $this; + } + + /** + * @param $name + * @return $this + */ + public function with($name): static + { + if (empty($name)) { + return $this; + } + if (is_string($name)) { + $name = explode(',', $name); + } + foreach ($name as $val) { + array_push($this->with, $val); + } + return $this; + } + + + /** + * @param $sql + * @param array $params + * @return mixed + * @throws Exception + */ + public function execute($sql, array $params = []): Command + { + return $this->modelClass->getConnection()->createCommand($sql, $params); + } + + + /** + * @return ModelInterface|null + * @throws Exception + */ + public function first(): ModelInterface|null + { + $data = $this->execute($this->builder->one())->one(); + if (empty($data)) { + return NULL; + } + return $this->populate($data); + } + + + /** + * @return string + * @throws Exception + */ + public function toSql(): string + { + return $this->builder->get(); + } + + + /** + * @return array|Collection + */ + public function get(): Collection|array + { + return $this->all(); + } + + + /** + * @throws Exception + */ + public function flush(): array|bool|int|string|null + { + return $this->execute($this->builder->truncate())->exec(); + } + + + /** + * @param int $size + * @param callable $callback + * @return Pagination + * @throws Exception + */ + public function page(int $size, callable $callback): Pagination + { + $pagination = new Pagination($this); + $pagination->setOffset(0); + $pagination->setLimit($size); + $pagination->setCallback($callback); + return $pagination; + } + + /** + * @param string $field + * @param string $setKey + * + * @return array|null + * @throws Exception + */ + public function column(string $field, string $setKey = ''): ?array + { + return $this->all()->column($field, $setKey); + } + + /** + * @return array|Collection + * @throws + */ + public function all(): Collection|array + { + $data = $this->execute($this->builder->all())->all(); + if (!empty($this->with)) { + $this->getWith($this->modelClass); + } + $collect = new Collection($this, $data, $this->modelClass); + if ($this->asArray) { + return $collect->toArray(); + } + return $collect; + } + + /** + * @param $data + * @return ModelInterface + * @throws Exception + */ + public function populate($data): ModelInterface + { + return $this->getWith($this->modelClass::populate($data)); + } + + + /** + * @param ModelInterface $model + * @return ModelInterface + */ + public function getWith(ModelInterface $model): ModelInterface + { + if (empty($this->with) || !is_array($this->with)) { + return $model; + } + return $model->setWith($this->with); + } + + /** + * @return int + * @throws Exception + */ + public function count(): int + { + $data = $this->execute($this->builder->count())->one(); + if ($data && is_array($data)) { + return (int)array_shift($data); + } + return 0; + } + + + /** + * @param array $data + * @return array|Command|bool|int|string + * @throws Exception + */ + public function batchUpdate(array $data): Command|array|bool|int|string + { + $generate = $this->builder->update($data); + if (is_bool($generate)) { + return $generate; + } + return $this->execute(...$generate)->exec(); + } + + /** + * @param array $data + * @return bool + * @throws Exception + */ + public function batchInsert(array $data): bool + { + [$sql, $params] = $this->builder->insert($data, TRUE); + + + return $this->execute($sql, $params)->exec(); + } + + /** + * @param $filed + * + * @return null + * @throws Exception + */ + public function value($filed) + { + return $this->first()[$filed] ?? NULL; + } + + /** + * @return bool + * @throws Exception + */ + public function exists(): bool + { + return !empty($this->execute($this->builder->one())->fetchColumn()); + } + + + /** + * @param bool $getSql + * @return int|bool|string|null + * @throws Exception + */ + public function delete(bool $getSql = FALSE): int|bool|string|null + { + $sql = $this->builder->delete(); + if ($getSql === FALSE) { + return $this->execute($sql)->delete(); + } + return $sql; + } +} diff --git a/Affair/BeginTransaction.php b/Affair/BeginTransaction.php index bc78819..5fa1779 100644 --- a/Affair/BeginTransaction.php +++ b/Affair/BeginTransaction.php @@ -1,8 +1,8 @@ -addGetter($this->name, $class, $method); - return true; - } - - -} +addGetter($this->name, $class, $method); + return true; + } + + +} diff --git a/Annotation/Relation.php b/Annotation/Relation.php index 2a705c0..cc933e3 100644 --- a/Annotation/Relation.php +++ b/Annotation/Relation.php @@ -1,41 +1,41 @@ -addRelate($this->name, $class, $method); - return true; - } - -} +addRelate($this->name, $class, $method); + return true; + } + +} diff --git a/Annotation/Set.php b/Annotation/Set.php index 81ee091..77062a0 100644 --- a/Annotation/Set.php +++ b/Annotation/Set.php @@ -1,39 +1,39 @@ -addSetter($this->name, $class, $method); - return true; - } - - -} +addSetter($this->name, $class, $method); + return true; + } + + +} diff --git a/Base/AbstractCollection.php b/Base/AbstractCollection.php index cfd99a4..cc8a808 100644 --- a/Base/AbstractCollection.php +++ b/Base/AbstractCollection.php @@ -1,162 +1,162 @@ -query, $this->model, $this->_item); - } - - - /** - * Collection constructor. - * - * @param $query - * @param array $array - * @param ModelInterface|null $model - * @throws Exception - */ - public function __construct($query, array $array = [], ModelInterface $model = null) - { - $this->_item = $array; - $this->query = $query; - $this->model = $model; - - parent::__construct([]); - } - - - /** - * @return int - */ - #[Pure] public function getLength(): int - { - return count($this->_item); - } - - - /** - * @param $item - */ - public function setItems($item) - { - $this->_item = $item; - } - - - /** - * @param $model - */ - public function setModel($model) - { - $this->model = $model; - } - - /** - * @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 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; - } - - - /** - * @param mixed $offset - */ - #[ReturnTypeWillChange] public function offsetUnset(mixed $offset) - { - if ($this->offsetExists($offset)) { - unset($this->_item[$offset]); - } - } -} +query, $this->model, $this->_item); + } + + + /** + * Collection constructor. + * + * @param $query + * @param array $array + * @param ModelInterface|null $model + * @throws Exception + */ + public function __construct($query, array $array = [], ModelInterface $model = null) + { + $this->_item = $array; + $this->query = $query; + $this->model = $model; + + parent::__construct([]); + } + + + /** + * @return int + */ + #[Pure] public function getLength(): int + { + return count($this->_item); + } + + + /** + * @param $item + */ + public function setItems($item) + { + $this->_item = $item; + } + + + /** + * @param $model + */ + public function setModel($model) + { + $this->model = $model; + } + + /** + * @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 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; + } + + + /** + * @param mixed $offset + */ + #[ReturnTypeWillChange] public function offsetUnset(mixed $offset) + { + if ($this->offsetExists($offset)) { + unset($this->_item[$offset]); + } + } +} diff --git a/Base/CollectionIterator.php b/Base/CollectionIterator.php index 9e43792..ee2f6c2 100644 --- a/Base/CollectionIterator.php +++ b/Base/CollectionIterator.php @@ -1,61 +1,61 @@ -model = $model; - parent::__construct($array, $flags); - } - - - /** - * @param $current - * @return ModelInterface - * @throws Exception - */ - protected function newModel($current): ModelInterface - { - return $this->model->populates($current); - } - - - /** - * @throws Exception - */ - public function current(): ModelInterface - { - if (is_array($current = parent::current())) { - $current = $this->newModel($current); - } - return $current; - } - - -} +model = $model; + parent::__construct($array, $flags); + } + + + /** + * @param $current + * @return ModelInterface + * @throws Exception + */ + protected function newModel($current): ModelInterface + { + return $this->model->populates($current); + } + + + /** + * @throws Exception + */ + public function current(): ModelInterface + { + if (is_array($current = parent::current())) { + $current = $this->newModel($current); + } + return $current; + } + + +} diff --git a/Base/ConditionClassMap.php b/Base/ConditionClassMap.php index cb3eaa0..60aca36 100644 --- a/Base/ConditionClassMap.php +++ b/Base/ConditionClassMap.php @@ -1,71 +1,71 @@ - [ - 'class' => InCondition::class - ], - 'NOT IN' => [ - 'class' => NotInCondition::class - ], - 'LIKE' => [ - 'class' => LikeCondition::class - ], - 'NOT LIKE' => [ - 'class' => NotLikeCondition::class - ], - 'LLike' => [ - 'class' => LLikeCondition::class - ], - 'RLike' => [ - 'class' => RLikeCondition::class - ], - 'EQ' => [ - 'class' => MathematicsCondition::class, - 'type' => 'EQ' - ], - 'NEQ' => [ - 'class' => MathematicsCondition::class, - 'type' => 'NEQ' - ], - 'GT' => [ - 'class' => MathematicsCondition::class, - 'type' => 'GT' - ], - 'EGT' => [ - 'class' => MathematicsCondition::class, - 'type' => 'EGT' - ], - 'LT' => [ - 'class' => MathematicsCondition::class, - 'type' => 'LT' - ], - 'ELT' => [ - 'class' => MathematicsCondition::class, - 'type' => 'ELT' - ], - 'BETWEEN' => BetweenCondition::class, - 'NOT BETWEEN' => NotBetweenCondition::class, - ]; - -} + [ + 'class' => InCondition::class + ], + 'NOT IN' => [ + 'class' => NotInCondition::class + ], + 'LIKE' => [ + 'class' => LikeCondition::class + ], + 'NOT LIKE' => [ + 'class' => NotLikeCondition::class + ], + 'LLike' => [ + 'class' => LLikeCondition::class + ], + 'RLike' => [ + 'class' => RLikeCondition::class + ], + 'EQ' => [ + 'class' => MathematicsCondition::class, + 'type' => 'EQ' + ], + 'NEQ' => [ + 'class' => MathematicsCondition::class, + 'type' => 'NEQ' + ], + 'GT' => [ + 'class' => MathematicsCondition::class, + 'type' => 'GT' + ], + 'EGT' => [ + 'class' => MathematicsCondition::class, + 'type' => 'EGT' + ], + 'LT' => [ + 'class' => MathematicsCondition::class, + 'type' => 'LT' + ], + 'ELT' => [ + 'class' => MathematicsCondition::class, + 'type' => 'ELT' + ], + 'BETWEEN' => BetweenCondition::class, + 'NOT BETWEEN' => NotBetweenCondition::class, + ]; + +} diff --git a/Base/Getter.php b/Base/Getter.php index 1eeb178..fdcc484 100644 --- a/Base/Getter.php +++ b/Base/Getter.php @@ -1,35 +1,35 @@ -_classMapping[$class][$name] = $method; - } - - - /** - * @param $class - * @param null $name - * @return array|string|null - */ - public function getGetter($class, $name = null): null|array|string - { - if (!empty($name)) { - return $this->_classMapping[$class][$name] ?? null; - } - return $this->_classMapping[$class] ?? []; - } - -} +_classMapping[$class][$name] = $method; + } + + + /** + * @param $class + * @param null $name + * @return array|string|null + */ + public function getGetter($class, $name = null): null|array|string + { + if (!empty($name)) { + return $this->_classMapping[$class][$name] ?? null; + } + return $this->_classMapping[$class] ?? []; + } + +} diff --git a/Base/Model.php b/Base/Model.php index 049449d..f20a7f1 100644 --- a/Base/Model.php +++ b/Base/Model.php @@ -1,1090 +1,1090 @@ -getSetter(static::class, $name); - if (!empty($method)) { - $value = $this->{$method}($value); - } - return $value; - } - - - /** - * @param string $name - * @param $value - * @return mixed - * @throws ReflectionException - */ - private function _getter(string $name, $value): mixed - { - $data = di(Getter::class)->getGetter(static::class, $name); - if (empty($data)) { - return $this->_relater($name, $value); - } - return $this->{$data}($value); - } - - - /** - * @param string $name - * @param $value - * @return mixed - * @throws ReflectionException - * @throws Exception - */ - private function _relater(string $name, $value): mixed - { - $data = di(Relate::class)->getRelate(static::class, $name); - if (!empty($data)) { - $data = $this->{$data}(); - if ($data instanceof HasBase) { - return $data->get(); - } - return $data; - } - return $this->_decode($name, $value); - } - - - /** - * @param $data - * @return Model - */ - public function setWith($data): static - { - if (empty($data)) { - return $this; - } - $this->_with = $data; - return $this; - } - - - /** - * @return array|null - */ - public function getWith(): array|null - { - return $this->_with; - } - - - /** - * object init - */ - public function clean() - { - $this->_attributes = []; - $this->_oldAttributes = []; - } - - - /** - * @throws Exception - */ - public function init() - { - $an = Kiri::app()->getAnnotation(); - $an->injectProperty($this); - } - - - /** - * @return array - */ - public function getActions(): array - { - return $this->actions; - } - - - /** - * @return bool - */ - public function getIsNowExample(): bool - { - return $this->isNewExample === TRUE; - } - - - /** - * @param bool $bool - * @return $this - */ - public function setIsNowExample(bool $bool = FALSE): static - { - $this->isNewExample = $bool; - return $this; - } - - /** - * @return string - * @throws Exception - * get last exception or other error - */ - public function getLastError(): string - { - return Kiri::app()->getLogger()->getLastError('mysql'); - } - - - /** - * @return bool - * @throws Exception - */ - 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 null|string - * @throws Exception - */ - public function getPrimary(): ?string - { - if (!$this->hasPrimary()) { - return NULL; - } - return $this->primary; - } - - - /** - * @return bool - * @throws Exception - */ - public function hasPrimaryValue(): bool - { - if ($this->hasPrimary()) { - return !empty($this->{$this->getPrimary()}); - } - return false; - } - - - /** - * @return int|null - * @throws Exception - */ - public function getPrimaryValue(): ?int - { - if (!$this->hasPrimary()) { - return NULL; - } - return $this->getAttribute($this->primary); - } - - /** - * @param $param - * @param null $db - * @return Model|null - * @throws NotFindClassException - * @throws ReflectionException - * @throws Exception - */ - public static function findOne($param, $db = NULL): static|null - { - if (is_bool($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 = duplicate(static::class)->getPrimary(); - if (empty($columns)) { - $columns = static::makeNewInstance()->getColumns()->getFirstPrimary(); - } - return static::query()->where([$columns => $param])->first(); - } - - - /** - * @return static - * @throws ReflectionException - */ - private static function makeNewInstance(): static - { - return duplicate(static::class); - } - - - /** - * @param $condition - * @return static|null - * @throws NotFindClassException - * @throws ReflectionException - * @throws Exception - */ - public static function first($condition): ?static - { - return static::query()->where($condition)->first(); - } - - - /** - * @return ActiveQuery - */ - public static function query(): ActiveQuery - { - return new ActiveQuery(new static()); - } - - - /** - * @return Connection - */ - public function getConnection(): Connection - { - return Kiri::app()->get($this->connection); - } - - - /** - * @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 - { - if (empty($condition)) { - if (!$if_condition_is_null) { - return FALSE; - } - return (bool)static::query()->delete(); - } - $model = static::query()->ifNotWhere($if_condition_is_null)->where($condition); - if (!empty($attributes)) { - $model->bindParams($attributes); - } - return (bool)$model->delete(); - } - - - /** - * @return array - * @throws Exception - */ - public function getAttributes(): array - { - return $this->toArray(); - } - - /** - * @return array - */ - public function getOldAttributes(): array - { - return $this->_oldAttributes; - } - - /** - * @param $name - * @param $value - * @return mixed - * @throws ReflectionException - */ - public function setAttribute($name, $value): mixed - { - return $this->_attributes[$name] = $this->_setter($name, $value); - } - - /** - * @param $name - * @param $value - * @return mixed - * @throws ReflectionException - */ - public function setOldAttribute($name, $value): mixed - { - return $this->_oldAttributes[$name] = $this->_setter($name, $value); - } - - /** - * @param array $param - * @return $this - * @throws Exception - */ - public function setAttributes(array $param): static - { - if (empty($param)) { - return $this; - } - foreach ($param as $key => $attribute) { - $this->setAttribute($key, $attribute); - } - return $this; - } - - - /** - * @param $param - * @return $this - * @throws ReflectionException - */ - public function setOldAttributes($param): static - { - if (empty($param) || !is_array($param)) { - return $this; - } - foreach ($param as $key => $attribute) { - $this->setOldAttribute($key, $attribute); - } - return $this; - } - - /** - * @param $attributes - * @param $param - * @return $this|bool - * @throws Exception - */ - private function insert($param, $attributes): bool|static - { - [$sql, $param] = SqlBuilder::builder(static::query())->insert($param); - $dbConnection = $this->getConnection()->createCommand($sql, $param); - - $lastId = $dbConnection->save(); - - $lastId = $this->setPrimary((int)$lastId, $param); - - $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 (!isset($param[$primary]) || empty($param[$primary])) { - $this->setAttribute($primary, (int)$lastId); - } - return $this; - } - - - /** - * @param $fields - * @param $condition - * @param $param - * @return $this|bool - * @throws Exception - */ - private function updateInternal($fields, $condition, $param): bool|static - { - if (empty($param)) { - return TRUE; - } - if ($this->hasPrimary()) { - $condition = [$this->getPrimary() => $this->getPrimaryValue()]; - } - $generate = SqlBuilder::builder(static::query()->where($condition))->update($param); - if (is_bool($generate)) { - return $generate; - } - $command = $this->getConnection()->createCommand($generate[0], $generate[1]); - if ($command->save()) { - return $this->refresh()->afterSave($fields, $param); - } - return FALSE; - } - - /** - * @param null $data - * @return bool|$this - * @throws Exception - */ - public function save($data = NULL): static|bool - { - if (!is_null($data)) { - $this->_attributes = merge($this->_attributes, $data); - } - if (!$this->validator($this->rules()) || !$this->beforeSave($this)) { - return FALSE; - } - [$change, $condition, $fields] = $this->separation(); - if (!empty($this->_oldAttributes)) { - return $this->updateInternal($fields, $condition, $change); - } else { - return $this->insert($change, $fields); - } - } - - - /** - * @param $value - * @return $this - */ - public function populates($value): static - { - $this->_attributes = $value; - $this->_oldAttributes = $value; - $this->setIsNowExample(FALSE); - return $this; - } - - - /** - * @param array|null $rule - * @return bool - * @throws Exception - */ - public function validator(?array $rule): bool - { - if (empty($rule)) return TRUE; - $validate = $this->resolve($rule); - if (!$validate->validation()) { - return $this->addError($validate->getError(), 'mysql'); - } else { - return TRUE; - } - } - - /** - * @param $rule - * @return Validator - * @throws Exception - */ - private function resolve($rule): Validator - { - $validate = Validator::getInstance(); - $validate->setParams($this->_attributes); - $validate->setModel($this); - foreach ($rule as $val) { - $field = array_shift($val); - if (empty($val)) { - continue; - } - $validate->make($field, $val); - } - return $validate; - } - - /** - * @param string $name - * @return null - * @throws Exception - */ - public function getAttribute(string $name) - { - if ($this->hasAnnotation($name)) { - return $this->runAnnotation($name, $this->_attributes[$name]); - } - return $this->_attributes[$name] ?? NULL; - } - - - /** - * @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 - { - $_tmp = []; - $condition = []; - foreach ($this->_attributes as $key => $val) { - $oldValue = $this->_oldAttributes[$key] ?? NULL; - if ($val === $oldValue) { - $condition[$key] = $val; - } else { - $_tmp[$key] = $val; - } - } - return [$_tmp, $condition, array_keys($_tmp)]; - } - - - /** - * @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 - */ - public function getRelation(): ?Relation - { - return Kiri::getDi()->get(Relation::class); - } - - - /** - * @param $name - * @return array|string|null - * @throws Exception - */ - public function getRelate($name): null|array|string - { - return di(Relate::class)->getRelate(static::class, $name); - } - - - /** - * @param $attribute - * @return bool - * @throws Exception - */ - public function has($attribute): bool - { - return static::makeNewInstance()->getColumns()->hasField($attribute); - } - - /**ƒ - * @return string - * @throws Exception - */ - public function getTable(): string - { - $connection = static::getConnection(); - - $tablePrefix = $connection->tablePrefix; - if (empty($this->table)) { - throw new Exception('You need add static method `tableName` and return table name.'); - } - $table = trim($this->table, '{%}'); - if (!empty($tablePrefix) && !str_starts_with($table, $tablePrefix)) { - $table = $tablePrefix . $table; - } - return '`' . $connection->database . '`.' . $table; - } - - - /** - * @param $attributes - * @param $changeAttributes - * @return bool - * @throws Exception - */ - public function afterSave($attributes, $changeAttributes): bool - { - return TRUE; - } - - - /** - * @param $model - * @return bool - */ - public function beforeSave($model): bool - { - return TRUE; - } - - - /** - * @return static - */ - public function refresh(): static - { - $this->_oldAttributes = $this->_attributes; - return $this; - } - - /** - * @param $name - * @param $value - * @throws Exception - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst($name))) { - $this->{'set' . ucfirst($name)}($value); - } else { - $this->_attributes[$name] = $this->_setter($name, $value); - } - } - - - /** - * @param $name - * @return mixed - * @throws Exception - */ - public function __get($name): mixed - { - $method = 'get' . ucfirst($name); - if (method_exists($this, $method)) { - return $this->{$method}(); - } - $value = $this->_attributes[$name] ?? NULL; - - return $this->_getter($name, $value); - } - - - /** - * @param $name - * @param $value - * @return mixed - * @throws Exception - */ - private 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 string $type - * @return array - */ - protected function getAnnotation(string $type = self::GET): array - { - return $this->_annotations[$type] ?? []; - } - - - /** - * @param $name - * @param string $type - * @return bool - */ - protected function hasAnnotation($name, string $type = self::GET): bool - { - if (!isset($this->_annotations[$type])) { - return FALSE; - } - return isset($this->_annotations[$type][$name]); - } - - - /** - * @param $item - * @param $data - * @return array - */ - protected function resolveAttributes($item, $data): array - { - return call_user_func($item, $data); - } - - /** - * @param $name - * @return bool - */ - public function __isset($name): bool - { - return isset($this->_attributes[$name]); - } - - /** - * @param $call - * @return mixed - * @throws Exception - */ - private function resolveClass($call): mixed - { - if ($call instanceof HasOne) { - return $call->get(); - } else if ($call instanceof HasMany) { - return $call->get(); - } else { - return $call; - } - } - - - /** - * @param mixed $offset - * @return bool - * @throws Exception - */ - public function offsetExists(mixed $offset): bool - { - return isset($this->_attributes[$offset]) || isset($this->_oldAttributes[$offset]); - } - - /** - * @param mixed $offset - * @return mixed - * @throws Exception - */ - public function offsetGet(mixed $offset): mixed - { - return $this->__get($offset); - } - - /** - * @param mixed $offset - * @param mixed $value - * @throws Exception - */ - #[ReturnTypeWillChange] public function offsetSet(mixed $offset, mixed $value) - { - $this->__set($offset, $value); - } - - /** - * @param mixed $offset - * @throws Exception - */ - #[ReturnTypeWillChange] public function offsetUnset(mixed $offset) - { - if (!isset($this->_attributes[$offset]) - && !isset($this->_oldAttributes[$offset])) { - return; - } - unset($this->_attributes[$offset]); - unset($this->_oldAttributes[$offset]); - if (isset($this->_relate)) { - unset($this->_relate[$offset]); - } - } - - /** - * @return array - */ - public function unset(): array - { - $fields = func_get_args(); - $fields = array_shift($fields); - if (!is_array($fields)) { - $fields = explode(',', $fields); - } - - $array = array_combine($fields, $fields); - - return array_diff_assoc($array, $this->_attributes); - } - - - /** - * @return Columns - * @throws Exception - */ - public function getColumns(): Columns - { - return $this->getConnection()->getSchema()->getColumns() - ->table($this->getTable()); - } - - /** - * @param array $data - * @return static - * @throws - */ - public static function populate(array $data): static - { - $model = duplicate(static::class); - $model->_attributes = $data; - $model->_oldAttributes = $data; - $model->setIsNowExample(FALSE); - return $model; - } - - - /** - * @param $method - * @param $value - * @return Closure - */ - protected function dispatcher($method, $value): Closure - { - return function () use ($method, $value) { - return $this->{$method}($value); - }; - } - - - /** - * @param string $name - * @param array $arguments - * @return mixed - */ - public static function __callStatic(string $name, array $arguments) - { - return (new static())->{$name}(...$arguments); - } - -} +getSetter(static::class, $name); + if (!empty($method)) { + $value = $this->{$method}($value); + } + return $value; + } + + + /** + * @param string $name + * @param $value + * @return mixed + * @throws ReflectionException + */ + private function _getter(string $name, $value): mixed + { + $data = di(Getter::class)->getGetter(static::class, $name); + if (empty($data)) { + return $this->_relater($name, $value); + } + return $this->{$data}($value); + } + + + /** + * @param string $name + * @param $value + * @return mixed + * @throws ReflectionException + * @throws Exception + */ + private function _relater(string $name, $value): mixed + { + $data = di(Relate::class)->getRelate(static::class, $name); + if (!empty($data)) { + $data = $this->{$data}(); + if ($data instanceof HasBase) { + return $data->get(); + } + return $data; + } + return $this->_decode($name, $value); + } + + + /** + * @param $data + * @return Model + */ + public function setWith($data): static + { + if (empty($data)) { + return $this; + } + $this->_with = $data; + return $this; + } + + + /** + * @return array|null + */ + public function getWith(): array|null + { + return $this->_with; + } + + + /** + * object init + */ + public function clean() + { + $this->_attributes = []; + $this->_oldAttributes = []; + } + + + /** + * @throws Exception + */ + public function init() + { + $an = Kiri::app()->getAnnotation(); + $an->injectProperty($this); + } + + + /** + * @return array + */ + public function getActions(): array + { + return $this->actions; + } + + + /** + * @return bool + */ + public function getIsNowExample(): bool + { + return $this->isNewExample === TRUE; + } + + + /** + * @param bool $bool + * @return $this + */ + public function setIsNowExample(bool $bool = FALSE): static + { + $this->isNewExample = $bool; + return $this; + } + + /** + * @return string + * @throws Exception + * get last exception or other error + */ + public function getLastError(): string + { + return Kiri::app()->getLogger()->getLastError('mysql'); + } + + + /** + * @return bool + * @throws Exception + */ + 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 null|string + * @throws Exception + */ + public function getPrimary(): ?string + { + if (!$this->hasPrimary()) { + return NULL; + } + return $this->primary; + } + + + /** + * @return bool + * @throws Exception + */ + public function hasPrimaryValue(): bool + { + if ($this->hasPrimary()) { + return !empty($this->{$this->getPrimary()}); + } + return false; + } + + + /** + * @return int|null + * @throws Exception + */ + public function getPrimaryValue(): ?int + { + if (!$this->hasPrimary()) { + return NULL; + } + return $this->getAttribute($this->primary); + } + + /** + * @param $param + * @param null $db + * @return Model|null + * @throws NotFindClassException + * @throws ReflectionException + * @throws Exception + */ + public static function findOne($param, $db = NULL): static|null + { + if (is_bool($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 = duplicate(static::class)->getPrimary(); + if (empty($columns)) { + $columns = static::makeNewInstance()->getColumns()->getFirstPrimary(); + } + return static::query()->where([$columns => $param])->first(); + } + + + /** + * @return static + * @throws ReflectionException + */ + private static function makeNewInstance(): static + { + return duplicate(static::class); + } + + + /** + * @param $condition + * @return static|null + * @throws NotFindClassException + * @throws ReflectionException + * @throws Exception + */ + public static function first($condition): ?static + { + return static::query()->where($condition)->first(); + } + + + /** + * @return ActiveQuery + */ + public static function query(): ActiveQuery + { + return new ActiveQuery(new static()); + } + + + /** + * @return Connection + */ + public function getConnection(): Connection + { + return Kiri::app()->get($this->connection); + } + + + /** + * @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 + { + if (empty($condition)) { + if (!$if_condition_is_null) { + return FALSE; + } + return (bool)static::query()->delete(); + } + $model = static::query()->ifNotWhere($if_condition_is_null)->where($condition); + if (!empty($attributes)) { + $model->bindParams($attributes); + } + return (bool)$model->delete(); + } + + + /** + * @return array + * @throws Exception + */ + public function getAttributes(): array + { + return $this->toArray(); + } + + /** + * @return array + */ + public function getOldAttributes(): array + { + return $this->_oldAttributes; + } + + /** + * @param $name + * @param $value + * @return mixed + * @throws ReflectionException + */ + public function setAttribute($name, $value): mixed + { + return $this->_attributes[$name] = $this->_setter($name, $value); + } + + /** + * @param $name + * @param $value + * @return mixed + * @throws ReflectionException + */ + public function setOldAttribute($name, $value): mixed + { + return $this->_oldAttributes[$name] = $this->_setter($name, $value); + } + + /** + * @param array $param + * @return $this + * @throws Exception + */ + public function setAttributes(array $param): static + { + if (empty($param)) { + return $this; + } + foreach ($param as $key => $attribute) { + $this->setAttribute($key, $attribute); + } + return $this; + } + + + /** + * @param $param + * @return $this + * @throws ReflectionException + */ + public function setOldAttributes($param): static + { + if (empty($param) || !is_array($param)) { + return $this; + } + foreach ($param as $key => $attribute) { + $this->setOldAttribute($key, $attribute); + } + return $this; + } + + /** + * @param $attributes + * @param $param + * @return $this|bool + * @throws Exception + */ + private function insert($param, $attributes): bool|static + { + [$sql, $param] = SqlBuilder::builder(static::query())->insert($param); + $dbConnection = $this->getConnection()->createCommand($sql, $param); + + $lastId = $dbConnection->save(); + + $lastId = $this->setPrimary((int)$lastId, $param); + + $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 (!isset($param[$primary]) || empty($param[$primary])) { + $this->setAttribute($primary, (int)$lastId); + } + return $this; + } + + + /** + * @param $fields + * @param $condition + * @param $param + * @return $this|bool + * @throws Exception + */ + private function updateInternal($fields, $condition, $param): bool|static + { + if (empty($param)) { + return TRUE; + } + if ($this->hasPrimary()) { + $condition = [$this->getPrimary() => $this->getPrimaryValue()]; + } + $generate = SqlBuilder::builder(static::query()->where($condition))->update($param); + if (is_bool($generate)) { + return $generate; + } + $command = $this->getConnection()->createCommand($generate[0], $generate[1]); + if ($command->save()) { + return $this->refresh()->afterSave($fields, $param); + } + return FALSE; + } + + /** + * @param null $data + * @return bool|$this + * @throws Exception + */ + public function save($data = NULL): static|bool + { + if (!is_null($data)) { + $this->_attributes = merge($this->_attributes, $data); + } + if (!$this->validator($this->rules()) || !$this->beforeSave($this)) { + return FALSE; + } + [$change, $condition, $fields] = $this->separation(); + if (!empty($this->_oldAttributes)) { + return $this->updateInternal($fields, $condition, $change); + } else { + return $this->insert($change, $fields); + } + } + + + /** + * @param $value + * @return $this + */ + public function populates($value): static + { + $this->_attributes = $value; + $this->_oldAttributes = $value; + $this->setIsNowExample(FALSE); + return $this; + } + + + /** + * @param array|null $rule + * @return bool + * @throws Exception + */ + public function validator(?array $rule): bool + { + if (empty($rule)) return TRUE; + $validate = $this->resolve($rule); + if (!$validate->validation()) { + return $this->addError($validate->getError(), 'mysql'); + } else { + return TRUE; + } + } + + /** + * @param $rule + * @return Validator + * @throws Exception + */ + private function resolve($rule): Validator + { + $validate = Validator::getInstance(); + $validate->setParams($this->_attributes); + $validate->setModel($this); + foreach ($rule as $val) { + $field = array_shift($val); + if (empty($val)) { + continue; + } + $validate->make($field, $val); + } + return $validate; + } + + /** + * @param string $name + * @return null + * @throws Exception + */ + public function getAttribute(string $name) + { + if ($this->hasAnnotation($name)) { + return $this->runAnnotation($name, $this->_attributes[$name]); + } + return $this->_attributes[$name] ?? NULL; + } + + + /** + * @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 + { + $_tmp = []; + $condition = []; + foreach ($this->_attributes as $key => $val) { + $oldValue = $this->_oldAttributes[$key] ?? NULL; + if ($val === $oldValue) { + $condition[$key] = $val; + } else { + $_tmp[$key] = $val; + } + } + return [$_tmp, $condition, array_keys($_tmp)]; + } + + + /** + * @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 + */ + public function getRelation(): ?Relation + { + return Kiri::getDi()->get(Relation::class); + } + + + /** + * @param $name + * @return array|string|null + * @throws Exception + */ + public function getRelate($name): null|array|string + { + return di(Relate::class)->getRelate(static::class, $name); + } + + + /** + * @param $attribute + * @return bool + * @throws Exception + */ + public function has($attribute): bool + { + return static::makeNewInstance()->getColumns()->hasField($attribute); + } + + /**ƒ + * @return string + * @throws Exception + */ + public function getTable(): string + { + $connection = static::getConnection(); + + $tablePrefix = $connection->tablePrefix; + if (empty($this->table)) { + throw new Exception('You need add static method `tableName` and return table name.'); + } + $table = trim($this->table, '{%}'); + if (!empty($tablePrefix) && !str_starts_with($table, $tablePrefix)) { + $table = $tablePrefix . $table; + } + return '`' . $connection->database . '`.' . $table; + } + + + /** + * @param $attributes + * @param $changeAttributes + * @return bool + * @throws Exception + */ + public function afterSave($attributes, $changeAttributes): bool + { + return TRUE; + } + + + /** + * @param $model + * @return bool + */ + public function beforeSave($model): bool + { + return TRUE; + } + + + /** + * @return static + */ + public function refresh(): static + { + $this->_oldAttributes = $this->_attributes; + return $this; + } + + /** + * @param $name + * @param $value + * @throws Exception + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst($name))) { + $this->{'set' . ucfirst($name)}($value); + } else { + $this->_attributes[$name] = $this->_setter($name, $value); + } + } + + + /** + * @param $name + * @return mixed + * @throws Exception + */ + public function __get($name): mixed + { + $method = 'get' . ucfirst($name); + if (method_exists($this, $method)) { + return $this->{$method}(); + } + $value = $this->_attributes[$name] ?? NULL; + + return $this->_getter($name, $value); + } + + + /** + * @param $name + * @param $value + * @return mixed + * @throws Exception + */ + private 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 string $type + * @return array + */ + protected function getAnnotation(string $type = self::GET): array + { + return $this->_annotations[$type] ?? []; + } + + + /** + * @param $name + * @param string $type + * @return bool + */ + protected function hasAnnotation($name, string $type = self::GET): bool + { + if (!isset($this->_annotations[$type])) { + return FALSE; + } + return isset($this->_annotations[$type][$name]); + } + + + /** + * @param $item + * @param $data + * @return array + */ + protected function resolveAttributes($item, $data): array + { + return call_user_func($item, $data); + } + + /** + * @param $name + * @return bool + */ + public function __isset($name): bool + { + return isset($this->_attributes[$name]); + } + + /** + * @param $call + * @return mixed + * @throws Exception + */ + private function resolveClass($call): mixed + { + if ($call instanceof HasOne) { + return $call->get(); + } else if ($call instanceof HasMany) { + return $call->get(); + } else { + return $call; + } + } + + + /** + * @param mixed $offset + * @return bool + * @throws Exception + */ + public function offsetExists(mixed $offset): bool + { + return isset($this->_attributes[$offset]) || isset($this->_oldAttributes[$offset]); + } + + /** + * @param mixed $offset + * @return mixed + * @throws Exception + */ + public function offsetGet(mixed $offset): mixed + { + return $this->__get($offset); + } + + /** + * @param mixed $offset + * @param mixed $value + * @throws Exception + */ + #[ReturnTypeWillChange] public function offsetSet(mixed $offset, mixed $value) + { + $this->__set($offset, $value); + } + + /** + * @param mixed $offset + * @throws Exception + */ + #[ReturnTypeWillChange] public function offsetUnset(mixed $offset) + { + if (!isset($this->_attributes[$offset]) + && !isset($this->_oldAttributes[$offset])) { + return; + } + unset($this->_attributes[$offset]); + unset($this->_oldAttributes[$offset]); + if (isset($this->_relate)) { + unset($this->_relate[$offset]); + } + } + + /** + * @return array + */ + public function unset(): array + { + $fields = func_get_args(); + $fields = array_shift($fields); + if (!is_array($fields)) { + $fields = explode(',', $fields); + } + + $array = array_combine($fields, $fields); + + return array_diff_assoc($array, $this->_attributes); + } + + + /** + * @return Columns + * @throws Exception + */ + public function getColumns(): Columns + { + return $this->getConnection()->getSchema()->getColumns() + ->table($this->getTable()); + } + + /** + * @param array $data + * @return static + * @throws + */ + public static function populate(array $data): static + { + $model = duplicate(static::class); + $model->_attributes = $data; + $model->_oldAttributes = $data; + $model->setIsNowExample(FALSE); + return $model; + } + + + /** + * @param $method + * @param $value + * @return Closure + */ + protected function dispatcher($method, $value): Closure + { + return function () use ($method, $value) { + return $this->{$method}($value); + }; + } + + + /** + * @param string $name + * @param array $arguments + * @return mixed + */ + public static function __callStatic(string $name, array $arguments) + { + return (new static())->{$name}(...$arguments); + } + +} diff --git a/Base/Relate.php b/Base/Relate.php index b485680..c4ca1ba 100644 --- a/Base/Relate.php +++ b/Base/Relate.php @@ -1,36 +1,36 @@ -_classMapping[$class][$name] = $method; - } - - - /** - * @param $class - * @param $name - * @return null|array|string - */ - public function getRelate($class, $name = null): null|array|string - { - if (!empty($name)) { - return $this->_classMapping[$class][$name] ?? null; - } - return $this->_classMapping[$class] ?? []; - } - - -} +_classMapping[$class][$name] = $method; + } + + + /** + * @param $class + * @param $name + * @return null|array|string + */ + public function getRelate($class, $name = null): null|array|string + { + if (!empty($name)) { + return $this->_classMapping[$class][$name] ?? null; + } + return $this->_classMapping[$class] ?? []; + } + + +} diff --git a/Base/Setter.php b/Base/Setter.php index dce87f7..214f3ff 100644 --- a/Base/Setter.php +++ b/Base/Setter.php @@ -1,32 +1,32 @@ -_classMapping[$class][$name] = $method; - } - - - /** - * @param $class - * @param $name - * @return null|array|string - */ - public function getSetter($class, $name): null|array|string - { - return $this->_classMapping[$class][$name] ?? null; - } - -} +_classMapping[$class][$name] = $method; + } + + + /** + * @param $class + * @param $name + * @return null|array|string + */ + public function getSetter($class, $name): null|array|string + { + return $this->_classMapping[$class][$name] ?? null; + } + +} diff --git a/Collection.php b/Collection.php index 48b8d6f..2818e94 100644 --- a/Collection.php +++ b/Collection.php @@ -1,243 +1,243 @@ -_item; - } - - /** - * @param $field - * - * @return array|null - * @throws Exception - */ - public function values($field): ?array - { - if (empty($field) || !is_string($field)) { - return NULL; - } - $_tmp = []; - $data = $this->toArray(); - foreach ($data as $val) { - /** @var ModelInterface $val */ - $_tmp[] = $val[$field]; - } - return $_tmp; - } - - /** - * @param string $field - * @return array|null - */ - public function keyBy(string $field): ?array - { - $array = $this->toArray(); - $column = array_flip(array_column($array, $field)); - foreach ($column as $key => $value) { - $column[$key] = $array[$value]; - } - - return $column; - } - - /** - * @return $this - */ - public function orderRand(): static - { - shuffle($this->_item); - return $this; - } - - /** - * @param int $start - * @param int $length - * - * @return array - */ - #[Pure] public function slice(int $start = 0, int $length = 20): array - { - if (empty($this->_item) || !is_array($this->_item)) { - return []; - } - if (count($this->_item) < $length) { - return $this->_item; - } else { - return array_slice($this->_item, $start, $length); - } - } - - /** - * @param string $field - * @param string $setKey - * - * @return array|null - */ - public function column(string $field, string $setKey = ''): ?array - { - $data = $this->toArray(); - if (empty($data)) { - return []; - } - if (!empty($setKey) && is_string($setKey)) { - return array_column($data, $field, $setKey); - } else { - return array_column($data, $field); - } - } - - /** - * @param string $field - * - * @return float|int|null - */ - public function sum(string $field): float|int|null - { - $array = $this->column($field); - if (empty($array)) { - return NULL; - } - return array_sum($array); - } - - /** - * @return ModelInterface|array - */ - #[Pure] public function current(): ModelInterface|array - { - return current($this->_item); - } - - /** - * @return int - */ - #[Pure] public function size(): int - { - return (int)count($this->_item); - } - - /** - * @return array - * @throws - */ - public function toArray(): array - { - $array = []; - /** @var Model $value */ - foreach ($this as $value) { - if (!is_object($value)) { - continue; - } - $array[] = $value->setWith($this->query->with)->toArray(); - } - $this->_item = []; - return $array; - } - - /** - * @throws Exception - * 批量删除 - */ - public function delete(): bool - { - $model = $this->getModel(); - if (!$model->hasPrimary()) return false; - $ids = []; - foreach ($this as $item) { - $id = $item->getPrimaryValue(); - if (!empty($id)) { - $ids[] = $id; - } - } - return $model::query()->whereIn($model->getPrimary(), $ids)->delete(); - } - - /** - * @param array $condition - * @return Collection - * @throws - */ - public function filter(array $condition): Collection|static - { - $_filters = []; - if (empty($condition)) { - return $this; - } - foreach ($this as $value) { - if (!$this->filterCheck($value, $condition)) { - continue; - } - $_filters[] = $value; - } - return new Collection($this->query, $_filters, $this->model); - } - - - /** - * @param $value - * @param $condition - * @return bool - * @throws Exception - */ - private function filterCheck($value, $condition): bool - { - $_value = $value; - if ($_value instanceof ModelInterface) { - $_value = $_value->toArray(); - } - $_tmp = array_intersect_key($_value, $condition); - if (count(array_diff_assoc($_tmp, $condition)) > 0) { - return false; - } - return true; - } - - - /** - * @param $key - * @param $value - * @return mixed - */ - public function exists($key, $value): mixed - { - foreach ($this as $item) { - if ($item->$key === $value) { - return $item; - } - } - return null; - } - - /** - * @return bool - */ - #[Pure] public function isEmpty(): bool - { - return $this->size() < 1; - } -} +_item; + } + + /** + * @param $field + * + * @return array|null + * @throws Exception + */ + public function values($field): ?array + { + if (empty($field) || !is_string($field)) { + return NULL; + } + $_tmp = []; + $data = $this->toArray(); + foreach ($data as $val) { + /** @var ModelInterface $val */ + $_tmp[] = $val[$field]; + } + return $_tmp; + } + + /** + * @param string $field + * @return array|null + */ + public function keyBy(string $field): ?array + { + $array = $this->toArray(); + $column = array_flip(array_column($array, $field)); + foreach ($column as $key => $value) { + $column[$key] = $array[$value]; + } + + return $column; + } + + /** + * @return $this + */ + public function orderRand(): static + { + shuffle($this->_item); + return $this; + } + + /** + * @param int $start + * @param int $length + * + * @return array + */ + #[Pure] public function slice(int $start = 0, int $length = 20): array + { + if (empty($this->_item) || !is_array($this->_item)) { + return []; + } + if (count($this->_item) < $length) { + return $this->_item; + } else { + return array_slice($this->_item, $start, $length); + } + } + + /** + * @param string $field + * @param string $setKey + * + * @return array|null + */ + public function column(string $field, string $setKey = ''): ?array + { + $data = $this->toArray(); + if (empty($data)) { + return []; + } + if (!empty($setKey) && is_string($setKey)) { + return array_column($data, $field, $setKey); + } else { + return array_column($data, $field); + } + } + + /** + * @param string $field + * + * @return float|int|null + */ + public function sum(string $field): float|int|null + { + $array = $this->column($field); + if (empty($array)) { + return NULL; + } + return array_sum($array); + } + + /** + * @return ModelInterface|array + */ + #[Pure] public function current(): ModelInterface|array + { + return current($this->_item); + } + + /** + * @return int + */ + #[Pure] public function size(): int + { + return (int)count($this->_item); + } + + /** + * @return array + * @throws + */ + public function toArray(): array + { + $array = []; + /** @var Model $value */ + foreach ($this as $value) { + if (!is_object($value)) { + continue; + } + $array[] = $value->setWith($this->query->with)->toArray(); + } + $this->_item = []; + return $array; + } + + /** + * @throws Exception + * 批量删除 + */ + public function delete(): bool + { + $model = $this->getModel(); + if (!$model->hasPrimary()) return false; + $ids = []; + foreach ($this as $item) { + $id = $item->getPrimaryValue(); + if (!empty($id)) { + $ids[] = $id; + } + } + return $model::query()->whereIn($model->getPrimary(), $ids)->delete(); + } + + /** + * @param array $condition + * @return Collection + * @throws + */ + public function filter(array $condition): Collection|static + { + $_filters = []; + if (empty($condition)) { + return $this; + } + foreach ($this as $value) { + if (!$this->filterCheck($value, $condition)) { + continue; + } + $_filters[] = $value; + } + return new Collection($this->query, $_filters, $this->model); + } + + + /** + * @param $value + * @param $condition + * @return bool + * @throws Exception + */ + private function filterCheck($value, $condition): bool + { + $_value = $value; + if ($_value instanceof ModelInterface) { + $_value = $_value->toArray(); + } + $_tmp = array_intersect_key($_value, $condition); + if (count(array_diff_assoc($_tmp, $condition)) > 0) { + return false; + } + return true; + } + + + /** + * @param $key + * @param $value + * @return mixed + */ + public function exists($key, $value): mixed + { + foreach ($this as $item) { + if ($item->$key === $value) { + return $item; + } + } + return null; + } + + /** + * @return bool + */ + #[Pure] public function isEmpty(): bool + { + return $this->size() < 1; + } +} diff --git a/Command.php b/Command.php index ee638ba..aff1edb 100644 --- a/Command.php +++ b/Command.php @@ -1,195 +1,195 @@ -execute(static::EXECUTE); - } - - /** - * @return int|bool|array|string|null - * @throws Exception - */ - public function save(): int|bool|array|string|null - { - return $this->execute(static::EXECUTE); - } - - - /** - * @return int|bool|array|string|null - * @throws Exception - */ - public function all(): int|bool|array|string|null - { - return $this->execute(static::FETCH_ALL); - } - - /** - * @return array|bool|int|string|null - * @throws Exception - */ - public function one(): null|array|bool|int|string - { - return $this->execute(static::FETCH); - } - - /** - * @return int|bool|array|string|null - * @throws Exception - */ - public function fetchColumn(): int|bool|array|string|null - { - return $this->execute(static::FETCH_COLUMN); - } - - /** - * @return int|bool|array|string|null - * @throws Exception - */ - public function rowCount(): int|bool|array|string|null - { - return $this->execute(static::ROW_COUNT); - } - - /** - * @return int|bool|array|string|null - * @throws Exception - */ - public function flush(): int|bool|array|string|null - { - return $this->execute(static::EXECUTE); - } - - /** - * @param string $type - * @return int|bool|array|string|null - * @throws Exception - */ - private function execute(string $type): int|bool|array|string|null - { - try { - $time = microtime(true); - if ($type === static::EXECUTE) { - $result = $this->db->getConnect($this->sql)->execute($this->sql,$this->params); - } else { - $result = $this->search($type); - } - if (microtime(true) - $time >= 0.02) { - $this->warning('Mysql:' . Json::encode([$this->sql, $this->params]) . (microtime(true) - $time)); - } - } catch (\Throwable $exception) { - $result = $this->addError($this->sql . '. error: ' . $exception->getMessage(), 'mysql'); - } finally { - $this->db->release(); - return $result; - } - } - - - /** - * @param string $type - * @return array|int|bool|null - * @throws Exception - */ - private function search(string $type): array|int|bool|null - { - $pdo = $this->db->getConnect($this->sql); - if ($type === static::FETCH_COLUMN) { - $data = $pdo->fetchColumn($this->sql, $this->params); - } else if ($type === static::ROW_COUNT) { - $data = $pdo->count($this->sql, $this->params); - } else if ($type === static::FETCH_ALL) { - $data = $pdo->fetchAll($this->sql, $this->params); - } else { - $data = $pdo->fetch($this->sql, $this->params); - } - return $data; - } - - - /** - * @return int|bool|array|string|null - * @throws Exception - */ - public function delete(): int|bool|array|string|null - { - return $this->execute(static::EXECUTE); - } - - /** - * @return int|bool|array|string|null - * @throws Exception - */ - public function exec(): int|bool|array|string|null - { - return $this->execute(static::EXECUTE); - } - - /** - * @param array $data - * @return $this - */ - public function bindValues(array $data = []): static - { - if (!empty($data)) { - $this->params = array_merge($this->params, $data); - } - return $this; - } - - /** - * @param $sql - * @return $this - * @throws Exception - */ - public function setSql($sql): static - { - $this->sql = $sql; - return $this; - } - -} +execute(static::EXECUTE); + } + + /** + * @return int|bool|array|string|null + * @throws Exception + */ + public function save(): int|bool|array|string|null + { + return $this->execute(static::EXECUTE); + } + + + /** + * @return int|bool|array|string|null + * @throws Exception + */ + public function all(): int|bool|array|string|null + { + return $this->execute(static::FETCH_ALL); + } + + /** + * @return array|bool|int|string|null + * @throws Exception + */ + public function one(): null|array|bool|int|string + { + return $this->execute(static::FETCH); + } + + /** + * @return int|bool|array|string|null + * @throws Exception + */ + public function fetchColumn(): int|bool|array|string|null + { + return $this->execute(static::FETCH_COLUMN); + } + + /** + * @return int|bool|array|string|null + * @throws Exception + */ + public function rowCount(): int|bool|array|string|null + { + return $this->execute(static::ROW_COUNT); + } + + /** + * @return int|bool|array|string|null + * @throws Exception + */ + public function flush(): int|bool|array|string|null + { + return $this->execute(static::EXECUTE); + } + + /** + * @param string $type + * @return int|bool|array|string|null + * @throws Exception + */ + private function execute(string $type): int|bool|array|string|null + { + try { + $time = microtime(true); + if ($type === static::EXECUTE) { + $result = $this->db->getConnect($this->sql)->execute($this->sql,$this->params); + } else { + $result = $this->search($type); + } + if (microtime(true) - $time >= 0.02) { + $this->warning('Mysql:' . Json::encode([$this->sql, $this->params]) . (microtime(true) - $time)); + } + } catch (\Throwable $exception) { + $result = $this->addError($this->sql . '. error: ' . $exception->getMessage(), 'mysql'); + } finally { + $this->db->release(); + return $result; + } + } + + + /** + * @param string $type + * @return array|int|bool|null + * @throws Exception + */ + private function search(string $type): array|int|bool|null + { + $pdo = $this->db->getConnect($this->sql); + if ($type === static::FETCH_COLUMN) { + $data = $pdo->fetchColumn($this->sql, $this->params); + } else if ($type === static::ROW_COUNT) { + $data = $pdo->count($this->sql, $this->params); + } else if ($type === static::FETCH_ALL) { + $data = $pdo->fetchAll($this->sql, $this->params); + } else { + $data = $pdo->fetch($this->sql, $this->params); + } + return $data; + } + + + /** + * @return int|bool|array|string|null + * @throws Exception + */ + public function delete(): int|bool|array|string|null + { + return $this->execute(static::EXECUTE); + } + + /** + * @return int|bool|array|string|null + * @throws Exception + */ + public function exec(): int|bool|array|string|null + { + return $this->execute(static::EXECUTE); + } + + /** + * @param array $data + * @return $this + */ + public function bindValues(array $data = []): static + { + if (!empty($data)) { + $this->params = array_merge($this->params, $data); + } + return $this; + } + + /** + * @param $sql + * @return $this + * @throws Exception + */ + public function setSql($sql): static + { + $this->sql = $sql; + return $this; + } + +} diff --git a/Condition/BetweenCondition.php b/Condition/BetweenCondition.php index 017715c..c5c6f76 100644 --- a/Condition/BetweenCondition.php +++ b/Condition/BetweenCondition.php @@ -1,23 +1,23 @@ -column . ' BETWEEN ' . (int)$this->value[0] . ' AND ' . (int)$this->value[1]; - } - -} +column . ' BETWEEN ' . (int)$this->value[0] . ' AND ' . (int)$this->value[1]; + } + +} diff --git a/Condition/ChildCondition.php b/Condition/ChildCondition.php index 7280750..def3a6d 100644 --- a/Condition/ChildCondition.php +++ b/Condition/ChildCondition.php @@ -1,22 +1,22 @@ -column . ' ' . $this->opera . ' (' . $this->value . ')'; - } - -} +column . ' ' . $this->opera . ' (' . $this->value . ')'; + } + +} diff --git a/Condition/Condition.php b/Condition/Condition.php index 1d87343..f8267b7 100644 --- a/Condition/Condition.php +++ b/Condition/Condition.php @@ -1,82 +1,82 @@ -column = $column; - } - - /** - * @param string $opera - */ - public function setOpera(string $opera): void - { - $this->opera = $opera; - } - - /** - * @param $params - */ - public function setValue($params): void - { - if (is_array($params)) { - $values = []; - foreach ($params as $item => $value) { - $values[$item] = is_numeric($value) ? $value : '\'' . $value . '\''; - } - $this->value = $values; - } else { - $this->value = $this->checkIsSqlString($params); - } - } - - - /** - * @param $params - * @return int|string - */ - #[Pure] private function checkIsSqlString($params): int|string - { - if (is_numeric($params)) { - return $params; - } - - $check = ltrim($params, '('); - $check = strtolower(substr($check, 0, 6)); - if (in_array($check, ['update', 'select', 'insert', 'delete'])) { - return $params; - } else { - return sprintf('\'%s\'', $params); - } - } - - -} +column = $column; + } + + /** + * @param string $opera + */ + public function setOpera(string $opera): void + { + $this->opera = $opera; + } + + /** + * @param $params + */ + public function setValue($params): void + { + if (is_array($params)) { + $values = []; + foreach ($params as $item => $value) { + $values[$item] = is_numeric($value) ? $value : '\'' . $value . '\''; + } + $this->value = $values; + } else { + $this->value = $this->checkIsSqlString($params); + } + } + + + /** + * @param $params + * @return int|string + */ + #[Pure] private function checkIsSqlString($params): int|string + { + if (is_numeric($params)) { + return $params; + } + + $check = ltrim($params, '('); + $check = strtolower(substr($check, 0, 6)); + if (in_array($check, ['update', 'select', 'insert', 'delete'])) { + return $params; + } else { + return sprintf('\'%s\'', $params); + } + } + + +} diff --git a/Condition/DefaultCondition.php b/Condition/DefaultCondition.php index 79971e7..a141e13 100644 --- a/Condition/DefaultCondition.php +++ b/Condition/DefaultCondition.php @@ -1,24 +1,24 @@ -column, $this->opera, addslashes($this->value)); - } - -} +column, $this->opera, addslashes($this->value)); + } + +} diff --git a/Condition/HashCondition.php b/Condition/HashCondition.php index ad40874..8b6ad75 100644 --- a/Condition/HashCondition.php +++ b/Condition/HashCondition.php @@ -1,30 +1,30 @@ -value)) { - return ''; - } - foreach ($this->value as $key => $value) { - if (is_null($value)) continue; - - $array[] = sprintf("%s = '%s'", $key, addslashes($value)); - } - return implode(' AND ', $array); - } - -} +value)) { + return ''; + } + foreach ($this->value as $key => $value) { + if (is_null($value)) continue; + + $array[] = sprintf("%s = '%s'", $key, addslashes($value)); + } + return implode(' AND ', $array); + } + +} diff --git a/Condition/InCondition.php b/Condition/InCondition.php index c11cb48..96cc155 100644 --- a/Condition/InCondition.php +++ b/Condition/InCondition.php @@ -1,31 +1,31 @@ -value)) { - return sprintf('%s IN (%s)', $this->column, implode(',', $this->value)); - } else { - return sprintf('%s IN (%s)', $this->column, $this->value); - } - } - -} +value)) { + return sprintf('%s IN (%s)', $this->column, implode(',', $this->value)); + } else { + return sprintf('%s IN (%s)', $this->column, $this->value); + } + } + +} diff --git a/Condition/JsonCondition.php b/Condition/JsonCondition.php index 48c8166..61b9be9 100644 --- a/Condition/JsonCondition.php +++ b/Condition/JsonCondition.php @@ -1,20 +1,20 @@ -value)) { - $this->value = array_shift($this->value); - } - return $this->column . ' LIKE \'%' . addslashes($this->value) . '\''; - } - -} +value)) { + $this->value = array_shift($this->value); + } + return $this->column . ' LIKE \'%' . addslashes($this->value) . '\''; + } + +} diff --git a/Condition/LikeCondition.php b/Condition/LikeCondition.php index acb99f0..1412e94 100644 --- a/Condition/LikeCondition.php +++ b/Condition/LikeCondition.php @@ -1,28 +1,28 @@ -value)) { - $this->value = array_shift($this->value); - } - return $this->column . ' LIKE \'%' . addslashes($this->value) . '%\''; - } - -} +value)) { + $this->value = array_shift($this->value); + } + return $this->column . ' LIKE \'%' . addslashes($this->value) . '%\''; + } + +} diff --git a/Condition/MathematicsCondition.php b/Condition/MathematicsCondition.php index b5c45ca..0e5ec6c 100644 --- a/Condition/MathematicsCondition.php +++ b/Condition/MathematicsCondition.php @@ -1,78 +1,78 @@ -{strtolower($this->type)}((float)$this->value); - } - - /** - * @param $value - * @return string - */ - public function eq($value): string - { - return $this->column . ' = ' . $value; - } - - /** - * @param $value - * @return string - */ - public function neq($value): string - { - return $this->column . ' <> ' . $value; - } - - /** - * @param $value - * @return string - */ - public function gt($value): string - { - return $this->column . ' > ' . $value; - } - - /** - * @param $value - * @return string - */ - public function egt($value): string - { - return $this->column . ' >= ' . $value; - } - - - /** - * @param $value - * @return string - */ - public function lt($value): string - { - return $this->column . ' < ' . $value; - } - - /** - * @param $value - * @return string - */ - public function elt($value): string - { - return $this->column . ' <= ' . $value; - } - -} +{strtolower($this->type)}((float)$this->value); + } + + /** + * @param $value + * @return string + */ + public function eq($value): string + { + return $this->column . ' = ' . $value; + } + + /** + * @param $value + * @return string + */ + public function neq($value): string + { + return $this->column . ' <> ' . $value; + } + + /** + * @param $value + * @return string + */ + public function gt($value): string + { + return $this->column . ' > ' . $value; + } + + /** + * @param $value + * @return string + */ + public function egt($value): string + { + return $this->column . ' >= ' . $value; + } + + + /** + * @param $value + * @return string + */ + public function lt($value): string + { + return $this->column . ' < ' . $value; + } + + /** + * @param $value + * @return string + */ + public function elt($value): string + { + return $this->column . ' <= ' . $value; + } + +} diff --git a/Condition/NotBetweenCondition.php b/Condition/NotBetweenCondition.php index 872083b..65f38b0 100644 --- a/Condition/NotBetweenCondition.php +++ b/Condition/NotBetweenCondition.php @@ -1,22 +1,22 @@ -column . ' NOT BETWEEN ' . (int)$this->value[0] . ' AND ' . (int)$this->value[1]; - } - -} +column . ' NOT BETWEEN ' . (int)$this->value[0] . ' AND ' . (int)$this->value[1]; + } + +} diff --git a/Condition/NotInCondition.php b/Condition/NotInCondition.php index f5e0165..3d5acf7 100644 --- a/Condition/NotInCondition.php +++ b/Condition/NotInCondition.php @@ -1,28 +1,28 @@ -value)) { - return null; - } - $value = '\'' . implode('\',\'', $this->value) . '\''; - return '`' . $this->column . '` not in(' . $value . ')'; - } - -} +value)) { + return null; + } + $value = '\'' . implode('\',\'', $this->value) . '\''; + return '`' . $this->column . '` not in(' . $value . ')'; + } + +} diff --git a/Condition/NotLikeCondition.php b/Condition/NotLikeCondition.php index 9787d62..6798aac 100644 --- a/Condition/NotLikeCondition.php +++ b/Condition/NotLikeCondition.php @@ -1,28 +1,28 @@ -value)) { - $this->value = array_shift($this->value); - } - return $this->column . ' NOT LIKE \'%' . addslashes($this->value) . '%\''; - } - -} +value)) { + $this->value = array_shift($this->value); + } + return $this->column . ' NOT LIKE \'%' . addslashes($this->value) . '%\''; + } + +} diff --git a/Condition/OrCondition.php b/Condition/OrCondition.php index 06fee97..065958b 100644 --- a/Condition/OrCondition.php +++ b/Condition/OrCondition.php @@ -1,27 +1,27 @@ -oldParams), addslashes($this->value)); - } - -} +oldParams), addslashes($this->value)); + } + +} diff --git a/Condition/RLikeCondition.php b/Condition/RLikeCondition.php index 4f3aec6..1f35123 100644 --- a/Condition/RLikeCondition.php +++ b/Condition/RLikeCondition.php @@ -1,28 +1,28 @@ -value)) { - $this->value = array_shift($this->value); - } - return sprintf('%s LIKE \'%s\'', $this->column, addslashes($this->value)); - } - -} +value)) { + $this->value = array_shift($this->value); + } + return sprintf('%s LIKE \'%s\'', $this->column, addslashes($this->value)); + } + +} diff --git a/Connection.php b/Connection.php index 152b775..aa38568 100644 --- a/Connection.php +++ b/Connection.php @@ -1,333 +1,333 @@ -eventProvider->on(OnWorkerStop::class, [$this, 'clear_connection'], 0); - $this->eventProvider->on(OnWorkerExit::class, [$this, 'clear_connection'], 0); - $this->eventProvider->on(BeginTransaction::class, [$this, 'beginTransaction'], 0); - $this->eventProvider->on(Rollback::class, [$this, 'rollback'], 0); - $this->eventProvider->on(Commit::class, [$this, 'commit'], 0); - } - - - /** - * @param null $sql - * @return PDO - * @throws Exception - */ - public function getConnect($sql = NULL): PDO - { - return $this->getPdo($sql); - } - - - /** - * @throws Exception - */ - public function fill() - { - $connections = $this->connections(); - $pool = Config::get('databases.pool.max', 10); - - $connections->initConnections('Mysql:' . $this->cds, true, $pool); - if (!empty($this->slaveConfig) && $this->cds != $this->slaveConfig['cds']) { - $connections->initConnections('Mysql:' . $this->slaveConfig['cds'], false, $pool); - } - } - - - /** - * @param $sql - * @return PDO - * @throws Exception - */ - private function getPdo($sql): PDO - { - if ($this->isWrite($sql)) { - return $this->masterInstance(); - } else { - return $this->slaveInstance(); - } - } - - /** - * @return mixed - * @throws ReflectionException - * @throws NotFindClassException - * @throws Exception - */ - public function getSchema(): Schema - { - if ($this->_schema === null) { - $this->_schema = Kiri::createObject([ - 'class' => Schema::class, - 'db' => $this - ]); - } - return $this->_schema; - } - - /** - * @param $sql - * @return bool - */ - public function isWrite($sql): bool - { - if (empty($sql)) return false; - if (str_starts_with(strtolower($sql), 'select')) { - return false; - } - return true; - } - - /** - * @return mixed - * @throws Exception - */ - public function getCacheDriver(): mixed - { - if (!$this->enableCache) { - return null; - } - return Kiri::app()->get($this->cacheDriver); - } - - /** - * @return PDO - * @throws Exception - */ - public function masterInstance(): PDO - { - return $this->connections()->get([ - 'cds' => $this->cds, - 'username' => $this->username, - 'password' => $this->password, - 'attributes' => $this->attributes, - 'connect_timeout' => $this->connect_timeout, - 'read_timeout' => $this->read_timeout, - 'dbname' => $this->database, - 'pool' => $this->pool - ], true); - } - - /** - * @return PDO - * @throws Exception - */ - public function slaveInstance(): PDO - { - if (empty($this->slaveConfig) || Db::transactionsActive()) { - return $this->masterInstance(); - } - if ($this->slaveConfig['cds'] == $this->cds) { - return $this->masterInstance(); - } - return $this->connections()->get($this->slaveConfig, false); - } - - - /** - * @return \Kiri\Pool\Connection - * @throws Exception - */ - private function connections(): \Kiri\Pool\Connection - { - return Kiri::getDi()->get(\Kiri\Pool\Connection::class); - } - - - /** - * @return $this - * @throws Exception - */ - public function beginTransaction(): static - { - $this->connections()->beginTransaction($this->cds); - return $this; - } - - /** - * @return $this|bool - * @throws Exception - */ - public function inTransaction(): bool|static - { - return $this->connections()->inTransaction($this->cds); - } - - /** - * @throws Exception - * 事务回滚 - */ - public function rollback() - { - $this->connections()->rollback($this->cds); - $this->release(); - } - - /** - * @throws Exception - * 事务提交 - */ - public function commit() - { - $this->connections()->commit($this->cds); - $this->release(); - } - - /** - * @param $sql - * @return PDO - * @throws Exception - */ - public function refresh($sql): PDO - { - if ($this->isWrite($sql)) { - $instance = $this->masterInstance(); - } else { - $instance = $this->slaveInstance(); - } - return $instance; - } - - /** - * @param null $sql - * @param array $attributes - * @return Command - * @throws Exception - */ - public function createCommand($sql = null, array $attributes = []): Command - { - $command = new Command(['db' => $this, 'sql' => $sql]); - return $command->bindValues($attributes); - } - - - /** - * - * 回收链接 - * @throws - */ - public function release() - { - if (!Kiri::isWorker() && !Kiri::isProcess()) { - $this->clear_connection(); - return; - } - $connections = $this->connections(); - $connections->release($this->cds, true); - $connections->release($this->slaveConfig['cds'], false); - } - - - /** - * @throws Exception - */ - public function recovery() - { - $connections = $this->connections(); - - $connections->release($this->cds, true); - $connections->release($this->slaveConfig['cds'], false); - } - - /** - * - * 回收链接 - * @throws - */ - public function clear_connection() - { - $connections = $this->connections(); - - $connections->connection_clear($this->cds, true); - $connections->connection_clear($this->slaveConfig['cds'], false); - } - - - /** - * @throws Exception - */ - public function disconnect() - { - $connections = $this->connections(); - $connections->disconnect($this->cds, true); - $connections->disconnect($this->slaveConfig['cds'], false); - } - -} +eventProvider->on(OnWorkerStop::class, [$this, 'clear_connection'], 0); + $this->eventProvider->on(OnWorkerExit::class, [$this, 'clear_connection'], 0); + $this->eventProvider->on(BeginTransaction::class, [$this, 'beginTransaction'], 0); + $this->eventProvider->on(Rollback::class, [$this, 'rollback'], 0); + $this->eventProvider->on(Commit::class, [$this, 'commit'], 0); + } + + + /** + * @param null $sql + * @return PDO + * @throws Exception + */ + public function getConnect($sql = NULL): PDO + { + return $this->getPdo($sql); + } + + + /** + * @throws Exception + */ + public function fill() + { + $connections = $this->connections(); + $pool = Config::get('databases.pool.max', 10); + + $connections->initConnections('Mysql:' . $this->cds, true, $pool); + if (!empty($this->slaveConfig) && $this->cds != $this->slaveConfig['cds']) { + $connections->initConnections('Mysql:' . $this->slaveConfig['cds'], false, $pool); + } + } + + + /** + * @param $sql + * @return PDO + * @throws Exception + */ + private function getPdo($sql): PDO + { + if ($this->isWrite($sql)) { + return $this->masterInstance(); + } else { + return $this->slaveInstance(); + } + } + + /** + * @return mixed + * @throws ReflectionException + * @throws NotFindClassException + * @throws Exception + */ + public function getSchema(): Schema + { + if ($this->_schema === null) { + $this->_schema = Kiri::createObject([ + 'class' => Schema::class, + 'db' => $this + ]); + } + return $this->_schema; + } + + /** + * @param $sql + * @return bool + */ + public function isWrite($sql): bool + { + if (empty($sql)) return false; + if (str_starts_with(strtolower($sql), 'select')) { + return false; + } + return true; + } + + /** + * @return mixed + * @throws Exception + */ + public function getCacheDriver(): mixed + { + if (!$this->enableCache) { + return null; + } + return Kiri::app()->get($this->cacheDriver); + } + + /** + * @return PDO + * @throws Exception + */ + public function masterInstance(): PDO + { + return $this->connections()->get([ + 'cds' => $this->cds, + 'username' => $this->username, + 'password' => $this->password, + 'attributes' => $this->attributes, + 'connect_timeout' => $this->connect_timeout, + 'read_timeout' => $this->read_timeout, + 'dbname' => $this->database, + 'pool' => $this->pool + ], true); + } + + /** + * @return PDO + * @throws Exception + */ + public function slaveInstance(): PDO + { + if (empty($this->slaveConfig) || Db::transactionsActive()) { + return $this->masterInstance(); + } + if ($this->slaveConfig['cds'] == $this->cds) { + return $this->masterInstance(); + } + return $this->connections()->get($this->slaveConfig, false); + } + + + /** + * @return \Kiri\Pool\Connection + * @throws Exception + */ + private function connections(): \Kiri\Pool\Connection + { + return Kiri::getDi()->get(\Kiri\Pool\Connection::class); + } + + + /** + * @return $this + * @throws Exception + */ + public function beginTransaction(): static + { + $this->connections()->beginTransaction($this->cds); + return $this; + } + + /** + * @return $this|bool + * @throws Exception + */ + public function inTransaction(): bool|static + { + return $this->connections()->inTransaction($this->cds); + } + + /** + * @throws Exception + * 事务回滚 + */ + public function rollback() + { + $this->connections()->rollback($this->cds); + $this->release(); + } + + /** + * @throws Exception + * 事务提交 + */ + public function commit() + { + $this->connections()->commit($this->cds); + $this->release(); + } + + /** + * @param $sql + * @return PDO + * @throws Exception + */ + public function refresh($sql): PDO + { + if ($this->isWrite($sql)) { + $instance = $this->masterInstance(); + } else { + $instance = $this->slaveInstance(); + } + return $instance; + } + + /** + * @param null $sql + * @param array $attributes + * @return Command + * @throws Exception + */ + public function createCommand($sql = null, array $attributes = []): Command + { + $command = new Command(['db' => $this, 'sql' => $sql]); + return $command->bindValues($attributes); + } + + + /** + * + * 回收链接 + * @throws + */ + public function release() + { + if (!Kiri::isWorker() && !Kiri::isProcess()) { + $this->clear_connection(); + return; + } + $connections = $this->connections(); + $connections->release($this->cds, true); + $connections->release($this->slaveConfig['cds'], false); + } + + + /** + * @throws Exception + */ + public function recovery() + { + $connections = $this->connections(); + + $connections->release($this->cds, true); + $connections->release($this->slaveConfig['cds'], false); + } + + /** + * + * 回收链接 + * @throws + */ + public function clear_connection() + { + $connections = $this->connections(); + + $connections->connection_clear($this->cds, true); + $connections->connection_clear($this->slaveConfig['cds'], false); + } + + + /** + * @throws Exception + */ + public function disconnect() + { + $connections = $this->connections(); + $connections->disconnect($this->cds, true); + $connections->disconnect($this->slaveConfig['cds'], false); + } + +} diff --git a/DatabasesProviders.php b/DatabasesProviders.php index 4d72513..9a68463 100644 --- a/DatabasesProviders.php +++ b/DatabasesProviders.php @@ -1,91 +1,91 @@ -eventProvider->on(OnWorkerStart::class, [$this, 'createPool']); - } - - - /** - * @param $name - * @return Connection - * @throws Exception - */ - public function get($name): Connection - { - return Kiri::app()->get($name); - } - - - /** - * @throws ConfigException - * @throws Exception - */ - public function createPool(OnWorkerStart $onWorkerStart) - { - $databases = Config::get('databases.connections', []); - if (empty($databases)) { - return; - } - - $app = Kiri::app(); - foreach ($databases as $key => $database) { - $database = $this->_settings($database); - - $connection = Kiri::getDi()->create(Connection::class, $database); - $connection->fill(); - - $app->set($key, $connection); - } - } - - - /** - * @param $database - * @return array - */ - private function _settings($database): array - { - $clientPool = $database['pool'] ?? ['min' => 1, 'max' => 5, 'tick' => 60]; - return [ - 'id' => $database['id'], - 'cds' => $database['cds'], - 'username' => $database['username'], - 'password' => $database['password'], - 'tablePrefix' => $database['tablePrefix'], - 'database' => $database['database'], - 'connect_timeout' => $database['connect_timeout'] ?? 30, - 'read_timeout' => $database['read_timeout'] ?? 10, - 'pool' => $clientPool, - 'attributes' => $database['attributes'] ?? [], - 'charset' => $database['charset'] ?? 'utf8mb4', - 'slaveConfig' => $database['slaveConfig'] - ]; - } - - -} +eventProvider->on(OnWorkerStart::class, [$this, 'createPool']); + } + + + /** + * @param $name + * @return Connection + * @throws Exception + */ + public function get($name): Connection + { + return Kiri::app()->get($name); + } + + + /** + * @throws ConfigException + * @throws Exception + */ + public function createPool(OnWorkerStart $onWorkerStart) + { + $databases = Config::get('databases.connections', []); + if (empty($databases)) { + return; + } + + $app = Kiri::app(); + foreach ($databases as $key => $database) { + $database = $this->_settings($database); + + $connection = Kiri::getDi()->create(Connection::class, $database); + $connection->fill(); + + $app->set($key, $connection); + } + } + + + /** + * @param $database + * @return array + */ + private function _settings($database): array + { + $clientPool = $database['pool'] ?? ['min' => 1, 'max' => 5, 'tick' => 60]; + return [ + 'id' => $database['id'], + 'cds' => $database['cds'], + 'username' => $database['username'], + 'password' => $database['password'], + 'tablePrefix' => $database['tablePrefix'], + 'database' => $database['database'], + 'connect_timeout' => $database['connect_timeout'] ?? 30, + 'read_timeout' => $database['read_timeout'] ?? 10, + 'pool' => $clientPool, + 'attributes' => $database['attributes'] ?? [], + 'charset' => $database['charset'] ?? 'utf8mb4', + 'slaveConfig' => $database['slaveConfig'] + ]; + } + + +} diff --git a/Db.php b/Db.php index dbd6232..7d56ec1 100644 --- a/Db.php +++ b/Db.php @@ -1,365 +1,365 @@ -dispatch(new BeginTransaction()); - } - static::$_inTransaction = true; - } - - - /** - * @throws Exception - */ - public static function commit() - { - if (static::transactionsActive()) { - di(EventDispatch::class)->dispatch(new Commit()); - } - static::$_inTransaction = false; - } - - - /** - * @throws Exception - */ - public static function rollback() - { - if (static::transactionsActive()) { - di(EventDispatch::class)->dispatch(new Rollback()); - } - static::$_inTransaction = false; - } - - - /** - * @param $table - * - * @return static - */ - public static function table($table): Db|static - { - $connection = new Db(); - $connection->from($table); - return $connection; - } - - - /** - * @param string $column - * @param string $alias - * @return string - */ - public static function any_value(string $column, string $alias = ''): string - { - if (empty($alias)) { - $alias = $column . '_any_value'; - } - return 'ANY_VALUE(' . $column . ') as ' . $alias; - } - - - /** - * @param string $column - * @return string - */ - public static function increment(string $column): string - { - return '+ ' . $column; - } - - - /** - * @param string $column - * @return string - */ - public static function decrement(string $column): string - { - return '- ' . $column; - } - - - /** - * @param Connection|null $connection - * @return mixed - * @throws Exception - */ - public function get(Connection $connection = NULL): mixed - { - $connection = static::getDefaultConnection($connection); - - return $connection->createCommand(SqlBuilder::builder($this)->one()) - ->all(); - } - - /** - * @param $column - * @return string - */ - public static function raw($column): string - { - return '`' . $column . '`'; - } - - /** - * @param Connection|null $connection - * @return mixed - * @throws Exception - */ - public function find(Connection $connection = NULL): mixed - { - $connection = static::getDefaultConnection($connection); - - return $connection->createCommand(SqlBuilder::builder($this)->all()) - ->one(); - } - - /** - * @param Connection|NULL $connection - * @return bool|int - * @throws Exception - */ - public function count(Connection $connection = NULL): bool|int - { - $connection = static::getDefaultConnection($connection); - - return $connection->createCommand(SqlBuilder::builder($this)->count()) - ->exec(); - } - - /** - * @param Connection|NULL $connection - * @return bool|int - * @throws Exception - */ - public function exists(Connection $connection = NULL): bool|int - { - $connection = static::getDefaultConnection($connection); - - return $connection->createCommand(SqlBuilder::builder($this)->one()) - ->fetchColumn(); - } - - /** - * @param string $sql - * @param array $attributes - * @param Connection|null $connection - * @return array|bool|int|string|null - * @throws Exception - */ - public static function findAllBySql(string $sql, array $attributes = [], Connection $connection = NULL): int|bool|array|string|null - { - $connection = static::getDefaultConnection($connection); - - return $connection->createCommand($sql, $attributes)->all(); - } - - /** - * @param string $sql - * @param array $attributes - * @param Connection|NULL $connection - * @return string|array|bool|int|null - * @throws Exception - */ - public static function findBySql(string $sql, array $attributes = [], Connection $connection = NULL): string|array|bool|int|null - { - $connection = static::getDefaultConnection($connection); - - return $connection->createCommand($sql, $attributes)->one(); - } - - /** - * @param string $field - * @return array|null - * @throws Exception - */ - public function values(string $field): ?array - { - $data = $this->get(); - if (empty($data) || empty($field)) { - return NULL; - } - $first = current($data); - if (!isset($first[$field])) { - return NULL; - } - return array_column($data, $field); - } - - /** - * @param $field - * @return mixed - * @throws Exception - */ - public function value($field): mixed - { - $data = $this->find(); - if (!empty($field) && isset($data[$field])) { - return $data[$field]; - } - return $data; - } - - /** - * @param Connection|null $connection - * @return bool|int - * @throws ConfigException - * @throws Exception - */ - public function delete(?Connection $connection = null): bool|int - { - $connection = static::getDefaultConnection($connection); - - return $connection->createCommand($connection->getBuild()->builder($this))->delete(); - } - - /** - * @param string $table - * @param null $connection - * @return bool|int - * @throws ConfigException - * @throws Exception - */ - public static function drop(string $table, $connection = null): bool|int - { - $connection = static::getDefaultConnection($connection); - - $sprint = sprintf('DROP TABLE `%s`.`%s`', $connection->database, $table); - return $connection->createCommand($sprint)->delete(); - } - - /** - * @param string $table - * @param null $connection - * @return bool|int - * @throws Exception - */ - public static function truncate(string $table, $connection = null): bool|int - { - $connection = static::getDefaultConnection($connection); - - $sprint = sprintf('TRUNCATE `%s`.`%s`', $connection->database, $table); - return $connection->createCommand($sprint)->exec(); - } - - /** - * @param string $table - * @param Connection|NULL $connection - * @return mixed - * @throws ConfigException - * @throws Exception - */ - public static function showCreateSql(string $table, Connection $connection = NULL): mixed - { - $connection = static::getDefaultConnection($connection); - - $sprint = sprintf('SHOW CREATE TABLE `%s`.`%s`', $connection->database, $table); - return $connection->createCommand($sprint)->one(); - } - - /** - * @param string $table - * @param Connection|NULL $connection - * @return bool|int|null - * @throws ConfigException - * @throws Exception - */ - public static function desc(string $table, Connection $connection = NULL): bool|int|null - { - $connection = static::getDefaultConnection($connection); - - $sprint = sprintf('SHOW FULL FIELDS FROM `%s`.`%s`', $connection->database, $table); - return $connection->createCommand($sprint)->all(); - } - - - /** - * @param string $table - * @param Connection|NULL $connection - * @return mixed - * @throws Exception - */ - public static function show(string $table, Connection $connection = NULL): mixed - { - if (empty($table)) { - return null; - } - $connection = static::getDefaultConnection($connection); - - $table = [' const TABLE = \'select * from %s where REFERENCED_TABLE_NAME=%s\';']; - return $connection->createCommand((new Query()) - ->select('*') - ->from('INFORMATION_SCHEMA.KEY_COLUMN_USAGE') - ->where(['REFERENCED_TABLE_NAME' => $table]) - ->getSql())->one(); - } - - - /** - * @param null|Connection $connection - * @param null $name - * @return mixed - * @throws ConfigException - * @throws Exception - */ - public static function getDefaultConnection(?Connection $connection, $name = null): Connection - { - if ($connection instanceof Connection) { - return $connection; - } - $databases = Config::get('databases.connections', []); - 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); - } - - -} +dispatch(new BeginTransaction()); + } + static::$_inTransaction = true; + } + + + /** + * @throws Exception + */ + public static function commit() + { + if (static::transactionsActive()) { + di(EventDispatch::class)->dispatch(new Commit()); + } + static::$_inTransaction = false; + } + + + /** + * @throws Exception + */ + public static function rollback() + { + if (static::transactionsActive()) { + di(EventDispatch::class)->dispatch(new Rollback()); + } + static::$_inTransaction = false; + } + + + /** + * @param $table + * + * @return static + */ + public static function table($table): Db|static + { + $connection = new Db(); + $connection->from($table); + return $connection; + } + + + /** + * @param string $column + * @param string $alias + * @return string + */ + public static function any_value(string $column, string $alias = ''): string + { + if (empty($alias)) { + $alias = $column . '_any_value'; + } + return 'ANY_VALUE(' . $column . ') as ' . $alias; + } + + + /** + * @param string $column + * @return string + */ + public static function increment(string $column): string + { + return '+ ' . $column; + } + + + /** + * @param string $column + * @return string + */ + public static function decrement(string $column): string + { + return '- ' . $column; + } + + + /** + * @param Connection|null $connection + * @return mixed + * @throws Exception + */ + public function get(Connection $connection = NULL): mixed + { + $connection = static::getDefaultConnection($connection); + + return $connection->createCommand(SqlBuilder::builder($this)->one()) + ->all(); + } + + /** + * @param $column + * @return string + */ + public static function raw($column): string + { + return '`' . $column . '`'; + } + + /** + * @param Connection|null $connection + * @return mixed + * @throws Exception + */ + public function find(Connection $connection = NULL): mixed + { + $connection = static::getDefaultConnection($connection); + + return $connection->createCommand(SqlBuilder::builder($this)->all()) + ->one(); + } + + /** + * @param Connection|NULL $connection + * @return bool|int + * @throws Exception + */ + public function count(Connection $connection = NULL): bool|int + { + $connection = static::getDefaultConnection($connection); + + return $connection->createCommand(SqlBuilder::builder($this)->count()) + ->exec(); + } + + /** + * @param Connection|NULL $connection + * @return bool|int + * @throws Exception + */ + public function exists(Connection $connection = NULL): bool|int + { + $connection = static::getDefaultConnection($connection); + + return $connection->createCommand(SqlBuilder::builder($this)->one()) + ->fetchColumn(); + } + + /** + * @param string $sql + * @param array $attributes + * @param Connection|null $connection + * @return array|bool|int|string|null + * @throws Exception + */ + public static function findAllBySql(string $sql, array $attributes = [], Connection $connection = NULL): int|bool|array|string|null + { + $connection = static::getDefaultConnection($connection); + + return $connection->createCommand($sql, $attributes)->all(); + } + + /** + * @param string $sql + * @param array $attributes + * @param Connection|NULL $connection + * @return string|array|bool|int|null + * @throws Exception + */ + public static function findBySql(string $sql, array $attributes = [], Connection $connection = NULL): string|array|bool|int|null + { + $connection = static::getDefaultConnection($connection); + + return $connection->createCommand($sql, $attributes)->one(); + } + + /** + * @param string $field + * @return array|null + * @throws Exception + */ + public function values(string $field): ?array + { + $data = $this->get(); + if (empty($data) || empty($field)) { + return NULL; + } + $first = current($data); + if (!isset($first[$field])) { + return NULL; + } + return array_column($data, $field); + } + + /** + * @param $field + * @return mixed + * @throws Exception + */ + public function value($field): mixed + { + $data = $this->find(); + if (!empty($field) && isset($data[$field])) { + return $data[$field]; + } + return $data; + } + + /** + * @param Connection|null $connection + * @return bool|int + * @throws ConfigException + * @throws Exception + */ + public function delete(?Connection $connection = null): bool|int + { + $connection = static::getDefaultConnection($connection); + + return $connection->createCommand($connection->getBuild()->builder($this))->delete(); + } + + /** + * @param string $table + * @param null $connection + * @return bool|int + * @throws ConfigException + * @throws Exception + */ + public static function drop(string $table, $connection = null): bool|int + { + $connection = static::getDefaultConnection($connection); + + $sprint = sprintf('DROP TABLE `%s`.`%s`', $connection->database, $table); + return $connection->createCommand($sprint)->delete(); + } + + /** + * @param string $table + * @param null $connection + * @return bool|int + * @throws Exception + */ + public static function truncate(string $table, $connection = null): bool|int + { + $connection = static::getDefaultConnection($connection); + + $sprint = sprintf('TRUNCATE `%s`.`%s`', $connection->database, $table); + return $connection->createCommand($sprint)->exec(); + } + + /** + * @param string $table + * @param Connection|NULL $connection + * @return mixed + * @throws ConfigException + * @throws Exception + */ + public static function showCreateSql(string $table, Connection $connection = NULL): mixed + { + $connection = static::getDefaultConnection($connection); + + $sprint = sprintf('SHOW CREATE TABLE `%s`.`%s`', $connection->database, $table); + return $connection->createCommand($sprint)->one(); + } + + /** + * @param string $table + * @param Connection|NULL $connection + * @return bool|int|null + * @throws ConfigException + * @throws Exception + */ + public static function desc(string $table, Connection $connection = NULL): bool|int|null + { + $connection = static::getDefaultConnection($connection); + + $sprint = sprintf('SHOW FULL FIELDS FROM `%s`.`%s`', $connection->database, $table); + return $connection->createCommand($sprint)->all(); + } + + + /** + * @param string $table + * @param Connection|NULL $connection + * @return mixed + * @throws Exception + */ + public static function show(string $table, Connection $connection = NULL): mixed + { + if (empty($table)) { + return null; + } + $connection = static::getDefaultConnection($connection); + + $table = [' const TABLE = \'select * from %s where REFERENCED_TABLE_NAME=%s\';']; + return $connection->createCommand((new Query()) + ->select('*') + ->from('INFORMATION_SCHEMA.KEY_COLUMN_USAGE') + ->where(['REFERENCED_TABLE_NAME' => $table]) + ->getSql())->one(); + } + + + /** + * @param null|Connection $connection + * @param null $name + * @return mixed + * @throws ConfigException + * @throws Exception + */ + public static function getDefaultConnection(?Connection $connection, $name = null): Connection + { + if ($connection instanceof Connection) { + return $connection; + } + $databases = Config::get('databases.connections', []); + 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); + } + + +} diff --git a/HasCount.php b/HasCount.php index 67d0dbf..b4ae522 100644 --- a/HasCount.php +++ b/HasCount.php @@ -1,39 +1,39 @@ -_relation->getQuery($this->model::className())->$name(...$arguments); - } - - /** - * @return array|null|ModelInterface - * @throws Exception - */ - public function get(): array|ModelInterface|null - { - return $this->_relation->count($this->model::className(), $this->value); - } - -} +_relation->getQuery($this->model::className())->$name(...$arguments); + } + + /** + * @return array|null|ModelInterface + * @throws Exception + */ + public function get(): array|ModelInterface|null + { + return $this->_relation->count($this->model::className(), $this->value); + } + +} diff --git a/HasMany.php b/HasMany.php index 933e9f4..24bc46f 100644 --- a/HasMany.php +++ b/HasMany.php @@ -1,44 +1,44 @@ -_relation->getQuery($this->model::className())->$name(...$arguments); - } - - /** - * @return array|null|ModelInterface - * @throws Exception - */ - public function get(): array|ModelInterface|null - { - return $this->_relation->get($this->model::className(), $this->value); - } -} +_relation->getQuery($this->model::className())->$name(...$arguments); + } + + /** + * @return array|null|ModelInterface + * @throws Exception + */ + public function get(): array|ModelInterface|null + { + return $this->_relation->get($this->model::className(), $this->value); + } +} diff --git a/HasOne.php b/HasOne.php index 24cc991..ef4c1a1 100644 --- a/HasOne.php +++ b/HasOne.php @@ -1,45 +1,45 @@ -_relation->getQuery($this->model::className())->$name(...$arguments); - return $this; - } - - /** - * @return array|null|ModelInterface - * @throws Exception - */ - public function get(): array|ModelInterface|null - { - return $this->_relation->first($this->model::className(), $this->value); - } -} +_relation->getQuery($this->model::className())->$name(...$arguments); + return $this; + } + + /** + * @return array|null|ModelInterface + * @throws Exception + */ + public function get(): array|ModelInterface|null + { + return $this->_relation->first($this->model::className(), $this->value); + } +} diff --git a/ISqlBuilder.php b/ISqlBuilder.php index f1fcc07..2cae7a3 100644 --- a/ISqlBuilder.php +++ b/ISqlBuilder.php @@ -1,10 +1,10 @@ -mathematics([$column => $value], '+')) { - return false; - } - $this->{$column} += $value; - return $this->refresh(); - } - - - /** - * @param string $column - * @param int $value - * @return ModelInterface|false - * @throws Exception - */ - public function decrement(string $column, int $value): bool|ModelInterface - { - if (!$this->mathematics([$column => $value], '-')) { - return false; - } - $this->{$column} -= $value; - return $this->refresh(); - } - - - /** - * @param array $columns - * @return ModelInterface|false - * @throws Exception - */ - public function increments(array $columns): bool|static - { - if (!$this->mathematics($columns, '+')) { - return false; - } - foreach ($columns as $key => $attribute) { - $this->$key += $attribute; - } - return $this; - } - - - /** - * @param array $columns - * @return ModelInterface|false - * @throws Exception - */ - public function decrements(array $columns): bool|static - { - if (!$this->mathematics($columns, '-')) { - return false; - } - foreach ($columns as $key => $attribute) { - $this->$key -= $attribute; - } - return $this; - } - - /** - * @param array $condition - * @param array $attributes - * @return bool|ModelInterface - * @throws ReflectionException - * @throws NotFindClassException - * @throws Exception - */ - public static function findOrCreate(array $condition, array $attributes): bool|static - { - $logger = Kiri::app()->getLogger(); - if (empty($attributes)) { - return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql'); - } - Db::beginTransaction(); - /** @var static $select */ - $select = static::query()->where($condition)->first(); - if (empty($select)) { - $select = duplicate(static::class); - $select->attributes = $attributes; - $select->setIsNowExample(true); - if (!$select->save()) { - Db::rollback(); - return $logger->addError($select->getLastError(), 'mysql'); - } - } - Db::commit(); - return $select; - } - - - /** - * @param array $condition - * @param array $attributes - * @return bool|static - * @throws Exception - */ - public static function createOrUpdate(array $condition, array $attributes = []): bool|static - { - $logger = Kiri::app()->getLogger(); - if (empty($attributes)) { - return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql'); - } - - Db::beginTransaction(); - /** @var static $select */ - $select = static::query()->where($condition)->first(); - if (empty($select)) { - $select = duplicate(static::class); - } - $select->attributes = $attributes; - if (!$select->save()) { - Db::rollback(); - $select = $logger->addError($select->getLastError(), 'mysql'); - } else { - Db::commit(); - } - return $select; - } - - - /** - * @param $action - * @param $columns - * @param null|array $condition - * @return array|bool|int|string|null - * @throws Exception - */ - private function mathematics($columns, $action, ?array $condition = null): int|bool|array|string|null - { - if (empty($condition)) { - $condition = [$this->getPrimary() => $this->getPrimaryValue()]; - } - - $activeQuery = static::query()->where($condition); - $create = SqlBuilder::builder($activeQuery)->mathematics($columns, $action); - if (is_bool($create)) { - return false; - } - return $this->getConnection()->createCommand($create[0], $create[1])->exec(); - } - - - /** - * @param array $fields - * @return ModelInterface|bool - * @throws Exception - */ - public function update(array $fields): static|bool - { - return $this->save($fields); - } - - - /** - * @param array $data - * @return bool - * @throws Exception - */ - public static function inserts(array $data): bool - { - $result = false; - if (empty($data)) { - error('Insert data empty.', 'mysql'); - } else { - $result = static::query()->batchInsert($data); - } - return $result; - } - - /** - * @return bool - * @throws Exception - */ - public function delete(): bool - { - $primary = $this->getPrimary(); - if (empty($primary) || !$this->hasPrimaryValue()) { - return $this->addError("Only primary key operations are supported.", 'mysql'); - } - if (!$this->beforeDelete()) { - $result = static::deleteByCondition([$primary => $this->getPrimaryValue()]); - Coroutine::create(function () use ($result) { - $this->afterDelete($result); - }); - return $result; - } - return false; - } - - - /** - * @param mixed $condition - * @param array $attributes - * - * @return bool - * @throws NotFindClassException - * @throws ReflectionException - * @throws Exception - */ - public static function updateAll(mixed $condition, array $attributes = []): bool - { - $condition = static::query()->where($condition); - return $condition->batchUpdate($attributes); - } - - - /** - * @param $condition - * @return array|Collection - * @throws NotFindClassException - * @throws ReflectionException - */ - public static function get($condition): Collection|array - { - return static::query()->where($condition)->all(); - } - - - /** - * @param $condition - * @param array $attributes - * - * @return array|Collection - * @throws Exception - */ - public static function findAll($condition, array $attributes = []): array|Collection - { - $query = static::query()->where($condition); - if (!empty($attributes)) { - $query->bindParams($attributes); - } - return $query->all(); - } - - /** - * @param $method - * @return mixed - * @throws Exception - */ - private function withRelation($method): mixed - { - $method = $this->getRelate($method); - if (empty($method)) { - return null; - } - $resolve = $this->{$method}(); - if ($resolve instanceof HasBase) { - $resolve = $resolve->get(); - } - if ($resolve instanceof ToArray) { - return $resolve->toArray(); - } else if (is_object($resolve)) { - return get_object_vars($resolve); - } else { - return $resolve; - } - } - - - /** - * @return array - * @throws Exception - */ - public function toArray(): array - { - $data = $this->_attributes; - $lists = di(Getter::class)->getGetter(static::class); - foreach ($lists as $key => $item) { - $data[$key] = $this->{$item}($data[$key] ?? null); - } - return $this->withRelates($data); - } - - /** - * @param $relates - * @return array - * @throws Exception - */ - private function withRelates($relates): array - { - if (empty($with = $this->getWith())) { - return $relates; - } - foreach ($with as $val) { - $relates[$val] = $this->withRelation($val); - } - return $relates; - } - - - /** - * @param string $modelName - * @param $foreignKey - * @param $localKey - * @return HasOne|ActiveQuery - * @throws Exception - */ - public function hasOne(string $modelName, $foreignKey, $localKey): HasOne|ActiveQuery - { - if (($value = $this->{$localKey}) === null) { - throw new Exception("Need join table primary key."); - } - - $relation = $this->getRelation(); - - return new HasOne($modelName, $foreignKey, $value, $relation); - } - - - /** - * @param $modelName - * @param $foreignKey - * @param $localKey - * @return ActiveQuery|HasCount - * @throws Exception - */ - public function hasCount($modelName, $foreignKey, $localKey): ActiveQuery|HasCount - { - if (($value = $this->{$localKey}) === null) { - throw new Exception("Need join table primary key."); - } - - $relation = $this->getRelation(); - - return new HasCount($modelName, $foreignKey, $value, $relation); - } - - - /** - * @param $modelName - * @param $foreignKey - * @param $localKey - * @return ActiveQuery|HasMany - * @throws Exception - */ - public function hasMany($modelName, $foreignKey, $localKey): ActiveQuery|HasMany - { - if (($value = $this->{$localKey}) === null) { - throw new Exception("Need join table primary key."); - } - - $relation = $this->getRelation(); - - return new HasMany($modelName, $foreignKey, $value, $relation); - } - - /** - * @param $modelName - * @param $foreignKey - * @param $localKey - * @return ActiveQuery|HasMany - * @throws Exception - */ - public function hasIn($modelName, $foreignKey, $localKey): ActiveQuery|HasMany - { - if (($value = $this->{$localKey}) === null) { - throw new Exception("Need join table primary key."); - } - - $relation = $this->getRelation(); - - return new HasMany($modelName, $foreignKey, $value, $relation); - } - - /** - * @param bool $result - * @return void - */ - public function afterDelete(bool $result): void - { - } - - /** - * @return bool - * @throws Exception - */ - public function beforeDelete(): bool - { - return TRUE; - } -} +mathematics([$column => $value], '+')) { + return false; + } + $this->{$column} += $value; + return $this->refresh(); + } + + + /** + * @param string $column + * @param int $value + * @return ModelInterface|false + * @throws Exception + */ + public function decrement(string $column, int $value): bool|ModelInterface + { + if (!$this->mathematics([$column => $value], '-')) { + return false; + } + $this->{$column} -= $value; + return $this->refresh(); + } + + + /** + * @param array $columns + * @return ModelInterface|false + * @throws Exception + */ + public function increments(array $columns): bool|static + { + if (!$this->mathematics($columns, '+')) { + return false; + } + foreach ($columns as $key => $attribute) { + $this->$key += $attribute; + } + return $this; + } + + + /** + * @param array $columns + * @return ModelInterface|false + * @throws Exception + */ + public function decrements(array $columns): bool|static + { + if (!$this->mathematics($columns, '-')) { + return false; + } + foreach ($columns as $key => $attribute) { + $this->$key -= $attribute; + } + return $this; + } + + /** + * @param array $condition + * @param array $attributes + * @return bool|ModelInterface + * @throws ReflectionException + * @throws NotFindClassException + * @throws Exception + */ + public static function findOrCreate(array $condition, array $attributes): bool|static + { + $logger = Kiri::app()->getLogger(); + if (empty($attributes)) { + return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql'); + } + Db::beginTransaction(); + /** @var static $select */ + $select = static::query()->where($condition)->first(); + if (empty($select)) { + $select = duplicate(static::class); + $select->attributes = $attributes; + $select->setIsNowExample(true); + if (!$select->save()) { + Db::rollback(); + return $logger->addError($select->getLastError(), 'mysql'); + } + } + Db::commit(); + return $select; + } + + + /** + * @param array $condition + * @param array $attributes + * @return bool|static + * @throws Exception + */ + public static function createOrUpdate(array $condition, array $attributes = []): bool|static + { + $logger = Kiri::app()->getLogger(); + if (empty($attributes)) { + return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql'); + } + + Db::beginTransaction(); + /** @var static $select */ + $select = static::query()->where($condition)->first(); + if (empty($select)) { + $select = duplicate(static::class); + } + $select->attributes = $attributes; + if (!$select->save()) { + Db::rollback(); + $select = $logger->addError($select->getLastError(), 'mysql'); + } else { + Db::commit(); + } + return $select; + } + + + /** + * @param $action + * @param $columns + * @param null|array $condition + * @return array|bool|int|string|null + * @throws Exception + */ + private function mathematics($columns, $action, ?array $condition = null): int|bool|array|string|null + { + if (empty($condition)) { + $condition = [$this->getPrimary() => $this->getPrimaryValue()]; + } + + $activeQuery = static::query()->where($condition); + $create = SqlBuilder::builder($activeQuery)->mathematics($columns, $action); + if (is_bool($create)) { + return false; + } + return $this->getConnection()->createCommand($create[0], $create[1])->exec(); + } + + + /** + * @param array $fields + * @return ModelInterface|bool + * @throws Exception + */ + public function update(array $fields): static|bool + { + return $this->save($fields); + } + + + /** + * @param array $data + * @return bool + * @throws Exception + */ + public static function inserts(array $data): bool + { + $result = false; + if (empty($data)) { + error('Insert data empty.', 'mysql'); + } else { + $result = static::query()->batchInsert($data); + } + return $result; + } + + /** + * @return bool + * @throws Exception + */ + public function delete(): bool + { + $primary = $this->getPrimary(); + if (empty($primary) || !$this->hasPrimaryValue()) { + return $this->addError("Only primary key operations are supported.", 'mysql'); + } + if (!$this->beforeDelete()) { + $result = static::deleteByCondition([$primary => $this->getPrimaryValue()]); + Coroutine::create(function () use ($result) { + $this->afterDelete($result); + }); + return $result; + } + return false; + } + + + /** + * @param mixed $condition + * @param array $attributes + * + * @return bool + * @throws NotFindClassException + * @throws ReflectionException + * @throws Exception + */ + public static function updateAll(mixed $condition, array $attributes = []): bool + { + $condition = static::query()->where($condition); + return $condition->batchUpdate($attributes); + } + + + /** + * @param $condition + * @return array|Collection + * @throws NotFindClassException + * @throws ReflectionException + */ + public static function get($condition): Collection|array + { + return static::query()->where($condition)->all(); + } + + + /** + * @param $condition + * @param array $attributes + * + * @return array|Collection + * @throws Exception + */ + public static function findAll($condition, array $attributes = []): array|Collection + { + $query = static::query()->where($condition); + if (!empty($attributes)) { + $query->bindParams($attributes); + } + return $query->all(); + } + + /** + * @param $method + * @return mixed + * @throws Exception + */ + private function withRelation($method): mixed + { + $method = $this->getRelate($method); + if (empty($method)) { + return null; + } + $resolve = $this->{$method}(); + if ($resolve instanceof HasBase) { + $resolve = $resolve->get(); + } + if ($resolve instanceof ToArray) { + return $resolve->toArray(); + } else if (is_object($resolve)) { + return get_object_vars($resolve); + } else { + return $resolve; + } + } + + + /** + * @return array + * @throws Exception + */ + public function toArray(): array + { + $data = $this->_attributes; + $lists = di(Getter::class)->getGetter(static::class); + foreach ($lists as $key => $item) { + $data[$key] = $this->{$item}($data[$key] ?? null); + } + return $this->withRelates($data); + } + + /** + * @param $relates + * @return array + * @throws Exception + */ + private function withRelates($relates): array + { + if (empty($with = $this->getWith())) { + return $relates; + } + foreach ($with as $val) { + $relates[$val] = $this->withRelation($val); + } + return $relates; + } + + + /** + * @param string $modelName + * @param $foreignKey + * @param $localKey + * @return HasOne|ActiveQuery + * @throws Exception + */ + public function hasOne(string $modelName, $foreignKey, $localKey): HasOne|ActiveQuery + { + if (($value = $this->{$localKey}) === null) { + throw new Exception("Need join table primary key."); + } + + $relation = $this->getRelation(); + + return new HasOne($modelName, $foreignKey, $value, $relation); + } + + + /** + * @param $modelName + * @param $foreignKey + * @param $localKey + * @return ActiveQuery|HasCount + * @throws Exception + */ + public function hasCount($modelName, $foreignKey, $localKey): ActiveQuery|HasCount + { + if (($value = $this->{$localKey}) === null) { + throw new Exception("Need join table primary key."); + } + + $relation = $this->getRelation(); + + return new HasCount($modelName, $foreignKey, $value, $relation); + } + + + /** + * @param $modelName + * @param $foreignKey + * @param $localKey + * @return ActiveQuery|HasMany + * @throws Exception + */ + public function hasMany($modelName, $foreignKey, $localKey): ActiveQuery|HasMany + { + if (($value = $this->{$localKey}) === null) { + throw new Exception("Need join table primary key."); + } + + $relation = $this->getRelation(); + + return new HasMany($modelName, $foreignKey, $value, $relation); + } + + /** + * @param $modelName + * @param $foreignKey + * @param $localKey + * @return ActiveQuery|HasMany + * @throws Exception + */ + public function hasIn($modelName, $foreignKey, $localKey): ActiveQuery|HasMany + { + if (($value = $this->{$localKey}) === null) { + throw new Exception("Need join table primary key."); + } + + $relation = $this->getRelation(); + + return new HasMany($modelName, $foreignKey, $value, $relation); + } + + /** + * @param bool $result + * @return void + */ + public function afterDelete(bool $result): void + { + } + + /** + * @return bool + * @throws Exception + */ + public function beforeDelete(): bool + { + return TRUE; + } +} diff --git a/ModelInterface.php b/ModelInterface.php index ed079a9..1ece44c 100644 --- a/ModelInterface.php +++ b/ModelInterface.php @@ -1,61 +1,61 @@ -structure($this->table = $table); - return $this; - } - - /** - * @return string - */ - public function getTable(): string - { - return $this->table; - } - - /** - * @param $key - * @param $val - * @return mixed - * @throws Exception - */ - public function fieldFormat($key, $val): mixed - { - return $this->encode($val, $this->get_fields($key)); - } - - /** - * @param $data - * @return array - * @throws - */ - public function populate($data): array - { - $column = $this->get_fields(); - foreach ($data as $key => $val) { - if (!isset($column[$key])) { - continue; - } - $data[$key] = $this->decode($val, $column[$key]); - } - return $data; - } - - /** - * @param $val - * @param null $format - * @return mixed - */ - public function decode($val, $format = null): mixed - { - if (empty($format) || $val === null) { - return $val; - } - $format = strtolower($format); - if ($this->isInt($format)) { - return (int)$val; - } else if ($this->isJson($format)) { - return Json::decode($val, true); - } else if ($this->isFloat($format)) { - return (float)$val; - } else { - return stripslashes($val); - } - } - - - /** - * @param string $name - * @param $value - * @return mixed - * @throws Exception - */ - public function _decode(string $name, $value): mixed - { - return $this->decode($value, $this->get_fields($name)); - } - - - /** - * @param $val - * @param null $format - * @return float|bool|int|string - * @throws Exception - */ - public function encode($val, $format = null): float|bool|int|string - { - if (empty($format)) { - return $val; - } - $format = strtolower($format); - if ($this->isInt($format)) { - return (int)$val; - } else if ($this->isJson($format)) { - return Json::encode($val); - } else if ($this->isFloat($format)) { - return (float)$val; - } else { - return addslashes($val); - } - } - - /** - * @param $format - * @return bool - */ - #[Pure] public function isInt($format): bool - { - return in_array($format, ['int', 'bigint', 'tinyint', 'smallint', 'mediumint']); - } - - /** - * @param $format - * @return bool - */ - #[Pure] public function isFloat($format): bool - { - return in_array($format, ['float', 'double', 'decimal']); - } - - /** - * @param $format - * @return bool - */ - #[Pure] public function isJson($format): bool - { - return in_array($format, ['json']); - } - - /** - * @param $format - * @return bool - */ - #[Pure] public function isString($format): bool - { - return in_array($format, ['varchar', 'char', 'text', 'longtext', 'tinytext', 'mediumtext']); - } - - - /** - * @return array - * @throws - */ - public function format(): array - { - return $this->columns('Default', 'Field'); - } - - - /** - * @return mixed - * @throws Exception - */ - public function getFields(): array - { - if (empty($this->_fields)) { - $this->structure($this->table); - } - return $this->_fields[$this->table]; - } - - - /** - * @param string $name - * @return bool - * @throws Exception - */ - public function hasField(string $name): bool - { - return array_key_exists($name, $this->getFields()); - } - - - /** - * @return int|string|null - * @throws Exception - */ - public function getAutoIncrement(): int|string|null - { - return $this->_auto_increment[$this->table] ?? null; - } - - /** - * @return array|null|string - * - * @throws Exception - */ - public function getPrimaryKeys(): array|string|null - { - if (isset($this->_auto_increment[$this->table])) { - return $this->_auto_increment[$this->table]; - } - return $this->_primary[$this->table] ?? null; - } - - /** - * @return array|null|string - * - * @throws Exception - */ - #[Pure] public function getFirstPrimary(): array|string|null - { - if (isset($this->_auto_increment[$this->table])) { - return $this->_auto_increment[$this->table]; - } - if (isset($this->_primary[$this->table])) { - return current($this->_primary[$this->table]); - } - return null; - } - - /** - * @param $name - * @param null $index - * @return array - * @throws Exception - */ - private function columns($name, $index = null): array - { - if (empty($index)) { - return array_column($this->getColumns(), $name); - } else { - return array_column($this->getColumns(), $name, $index); - } - } - - /** - * @return array|static - * @throws Exception - */ - private function getColumns(): array|static - { - return $this->structure($this->getTable()); - } - - - /** - * @param $table - * @return array|Columns - * @throws Exception - */ - private function structure($table): array|static - { - if (!isset($this->columns[$table]) || empty($this->columns[$table])) { - $column = $this->db->createCommand(SqlBuilder::builder(null)->columns($table))->all(); - if (empty($column)) { - throw new Exception("The table " . $table . " not exists."); - } - return $this->columns[$table] = $this->resolve($column, $table); - } - return $this->columns[$table]; - } - - - /** - * @param array $column - * @param $table - * @return array - */ - private function resolve(array $column, $table): array - { - foreach ($column as $key => $item) { - $this->addPrimary($item, $table); - $column[$key]['Type'] = $this->clean($item['Type']); - } - - $this->_fields[$table] = array_column($column, 'Default', 'Field'); - - return $column; - } - - /** - * @param $item - * @param $table - */ - private function addPrimary($item, $table) - { - if (!isset($this->_primary[$table])) { - $this->_primary[$table] = []; - } - if ($item['Key'] === 'PRI') { - $this->_primary[$table][] = $item['Field']; - } - $this->addIncrement($item, $table); - } - - - /** - * @param $item - * @param $table - */ - private function addIncrement($item, $table) - { - if ($item['Extra'] !== 'auto_increment') { - return; - } - $this->_auto_increment[$table] = $item['Field']; - } - - - /** - * @param $type - * @return string - */ - public function clean($type): string - { - if (!str_contains($type, ')')) { - return $type; - } - $replace = preg_replace('/\(\d+(,\d+)?\)(\s+\w+)*/', '', $type); - if (str_contains($replace, ' ')) { - $replace = explode(' ', $replace)[1]; - } - return $replace; - } - - /** - * @param null $field - * @return array|string|null - * @throws Exception - */ - public function get_fields($field = null): array|string|null - { - $fields = $this->getAllField(); - if (empty($field)) { - return $fields; - } - if (isset($fields[$field])) { - return strtolower($fields[$field]); - } - return null; - } - - /** - * @return array - * @throws Exception - */ - public function getAllField(): array - { - return $this->columns('Type', 'Field'); - } - -} +structure($this->table = $table); + return $this; + } + + /** + * @return string + */ + public function getTable(): string + { + return $this->table; + } + + /** + * @param $key + * @param $val + * @return mixed + * @throws Exception + */ + public function fieldFormat($key, $val): mixed + { + return $this->encode($val, $this->get_fields($key)); + } + + /** + * @param $data + * @return array + * @throws + */ + public function populate($data): array + { + $column = $this->get_fields(); + foreach ($data as $key => $val) { + if (!isset($column[$key])) { + continue; + } + $data[$key] = $this->decode($val, $column[$key]); + } + return $data; + } + + /** + * @param $val + * @param null $format + * @return mixed + */ + public function decode($val, $format = null): mixed + { + if (empty($format) || $val === null) { + return $val; + } + $format = strtolower($format); + if ($this->isInt($format)) { + return (int)$val; + } else if ($this->isJson($format)) { + return Json::decode($val, true); + } else if ($this->isFloat($format)) { + return (float)$val; + } else { + return stripslashes($val); + } + } + + + /** + * @param string $name + * @param $value + * @return mixed + * @throws Exception + */ + public function _decode(string $name, $value): mixed + { + return $this->decode($value, $this->get_fields($name)); + } + + + /** + * @param $val + * @param null $format + * @return float|bool|int|string + * @throws Exception + */ + public function encode($val, $format = null): float|bool|int|string + { + if (empty($format)) { + return $val; + } + $format = strtolower($format); + if ($this->isInt($format)) { + return (int)$val; + } else if ($this->isJson($format)) { + return Json::encode($val); + } else if ($this->isFloat($format)) { + return (float)$val; + } else { + return addslashes($val); + } + } + + /** + * @param $format + * @return bool + */ + #[Pure] public function isInt($format): bool + { + return in_array($format, ['int', 'bigint', 'tinyint', 'smallint', 'mediumint']); + } + + /** + * @param $format + * @return bool + */ + #[Pure] public function isFloat($format): bool + { + return in_array($format, ['float', 'double', 'decimal']); + } + + /** + * @param $format + * @return bool + */ + #[Pure] public function isJson($format): bool + { + return in_array($format, ['json']); + } + + /** + * @param $format + * @return bool + */ + #[Pure] public function isString($format): bool + { + return in_array($format, ['varchar', 'char', 'text', 'longtext', 'tinytext', 'mediumtext']); + } + + + /** + * @return array + * @throws + */ + public function format(): array + { + return $this->columns('Default', 'Field'); + } + + + /** + * @return mixed + * @throws Exception + */ + public function getFields(): array + { + if (empty($this->_fields)) { + $this->structure($this->table); + } + return $this->_fields[$this->table]; + } + + + /** + * @param string $name + * @return bool + * @throws Exception + */ + public function hasField(string $name): bool + { + return array_key_exists($name, $this->getFields()); + } + + + /** + * @return int|string|null + * @throws Exception + */ + public function getAutoIncrement(): int|string|null + { + return $this->_auto_increment[$this->table] ?? null; + } + + /** + * @return array|null|string + * + * @throws Exception + */ + public function getPrimaryKeys(): array|string|null + { + if (isset($this->_auto_increment[$this->table])) { + return $this->_auto_increment[$this->table]; + } + return $this->_primary[$this->table] ?? null; + } + + /** + * @return array|null|string + * + * @throws Exception + */ + #[Pure] public function getFirstPrimary(): array|string|null + { + if (isset($this->_auto_increment[$this->table])) { + return $this->_auto_increment[$this->table]; + } + if (isset($this->_primary[$this->table])) { + return current($this->_primary[$this->table]); + } + return null; + } + + /** + * @param $name + * @param null $index + * @return array + * @throws Exception + */ + private function columns($name, $index = null): array + { + if (empty($index)) { + return array_column($this->getColumns(), $name); + } else { + return array_column($this->getColumns(), $name, $index); + } + } + + /** + * @return array|static + * @throws Exception + */ + private function getColumns(): array|static + { + return $this->structure($this->getTable()); + } + + + /** + * @param $table + * @return array|Columns + * @throws Exception + */ + private function structure($table): array|static + { + if (!isset($this->columns[$table]) || empty($this->columns[$table])) { + $column = $this->db->createCommand(SqlBuilder::builder(null)->columns($table))->all(); + if (empty($column)) { + throw new Exception("The table " . $table . " not exists."); + } + return $this->columns[$table] = $this->resolve($column, $table); + } + return $this->columns[$table]; + } + + + /** + * @param array $column + * @param $table + * @return array + */ + private function resolve(array $column, $table): array + { + foreach ($column as $key => $item) { + $this->addPrimary($item, $table); + $column[$key]['Type'] = $this->clean($item['Type']); + } + + $this->_fields[$table] = array_column($column, 'Default', 'Field'); + + return $column; + } + + /** + * @param $item + * @param $table + */ + private function addPrimary($item, $table) + { + if (!isset($this->_primary[$table])) { + $this->_primary[$table] = []; + } + if ($item['Key'] === 'PRI') { + $this->_primary[$table][] = $item['Field']; + } + $this->addIncrement($item, $table); + } + + + /** + * @param $item + * @param $table + */ + private function addIncrement($item, $table) + { + if ($item['Extra'] !== 'auto_increment') { + return; + } + $this->_auto_increment[$table] = $item['Field']; + } + + + /** + * @param $type + * @return string + */ + public function clean($type): string + { + if (!str_contains($type, ')')) { + return $type; + } + $replace = preg_replace('/\(\d+(,\d+)?\)(\s+\w+)*/', '', $type); + if (str_contains($replace, ' ')) { + $replace = explode(' ', $replace)[1]; + } + return $replace; + } + + /** + * @param null $field + * @return array|string|null + * @throws Exception + */ + public function get_fields($field = null): array|string|null + { + $fields = $this->getAllField(); + if (empty($field)) { + return $fields; + } + if (isset($fields[$field])) { + return strtolower($fields[$field]); + } + return null; + } + + /** + * @return array + * @throws Exception + */ + public function getAllField(): array + { + return $this->columns('Type', 'Field'); + } + +} diff --git a/Mysql/PDO.php b/Mysql/PDO.php index 4ea5085..e033862 100644 --- a/Mysql/PDO.php +++ b/Mysql/PDO.php @@ -1,324 +1,324 @@ -dbname = $config['dbname']; - $this->cds = $config['cds']; - $this->username = $config['username']; - $this->password = $config['password']; - $this->connect_timeout = $config['connect_timeout'] ?? 30; - $this->read_timeout = $config['read_timeout'] ?? 10; - $this->charset = $config['charset'] ?? 'utf8mb4'; - $this->attributes = $config['attributes'] ?? []; - } - - - public function init() - { - $this->heartbeat_check(); - } - - - /** - * @return bool - */ - public function inTransaction(): bool - { - return $this->_transaction > 0; - } - - - /** - * - */ - public function heartbeat_check(): void - { - if (env('state', 'start') == 'exit') { - return; - } - if ($this->_timer === -1) { - $this->_timer = Timer::tick(1000, fn() => $this->waite()); - } - } - - - /** - * @throws Exception - */ - private function waite(): void - { - try { - if (env('state', 'start') == 'exit') { - Kiri::getDi()->get(Logger::class)->critical('timer end'); - $this->stopHeartbeatCheck(); - } - if (time() - $this->_last > (int)Config::get('databases.pool.tick', 60)) { - $this->stopHeartbeatCheck(); - $this->pdo = null; - } - } catch (\Throwable $throwable) { - error($throwable); - } - } - - - /** - * - */ - public function stopHeartbeatCheck(): void - { - if ($this->_timer > -1) { - Timer::clear($this->_timer); - } - $this->_timer = -1; - } - - - /** - * - */ - public function beginTransaction() - { - if ($this->_transaction == 0) { - $this->_pdo()->beginTransaction(); - } - $this->_transaction++; - } - - - /** - * - */ - public function commit() - { - if ($this->_transaction == 0) { - $this->_pdo()->commit(); - } - $this->_transaction--; - } - - - /** - * - */ - public function rollback() - { - if ($this->_transaction == 0) { - $this->_pdo()->rollBack(); - } - $this->_transaction--; - } - - - /** - * @param string $sql - * @param array $params - * @return bool|array|null - * @throws Exception - */ - public function fetchAll(string $sql, array $params = []): bool|null|array - { - $pdo = $this->queryPrev($sql, $params); - - $result = $pdo->fetchAll(\PDO::FETCH_ASSOC); - $pdo->closeCursor(); - return $result; - } - - - /** - * @param string $sql - * @param array $params - * @return bool|array|null - * @throws Exception - */ - public function fetch(string $sql, array $params = []): bool|null|array - { - $pdo = $this->queryPrev($sql, $params); - - $result = $pdo->fetch(\PDO::FETCH_ASSOC); - $pdo->closeCursor(); - return $result; - } - - - /** - * @param string $sql - * @param array $params - * @return bool|array|null - * @throws \Exception - */ - public function fetchColumn(string $sql, array $params = []): bool|null|array - { - $pdo = $this->queryPrev($sql, $params); - - $result = $pdo->fetchColumn(\PDO::FETCH_ASSOC); - $pdo->closeCursor(); - return $result; - } - - - /** - * @param string $sql - * @param array $params - * @return int - * @throws Exception - */ - public function count(string $sql, array $params = []): int - { - $pdo = $this->queryPrev($sql, $params); - - $result = $pdo->rowCount(); - $pdo->closeCursor(); - return $result; - } - - - /** - * @param string $sql - * @param array $params - * @return PDOStatement - * @throws Exception - */ - private function queryPrev(string $sql, array $params = []): PDOStatement - { - $this->_last = time(); - try { - if (($statement = $this->_pdo()->query($sql)) === false) { - throw new Exception($this->_pdo()->errorInfo()[1]); - } - return $this->bindValue($statement, $params); - } catch (\PDOException | \Throwable $throwable) { - if (str_contains($throwable->getMessage(), 'MySQL server has gone away')) { - $this->pdo = null; - - return $this->queryPrev($sql, $params); - } - throw new Exception($throwable->getMessage()); - } - } - - - /** - * @param PDOStatement $statement - * @param array $params - * @return PDOStatement - */ - private function bindValue(PDOStatement $statement, array $params = []): PDOStatement - { - if (empty($params)) return $statement; - foreach ($params as $key => $param) { - $statement->bindValue($key, $param); - } - return $statement; - } - - - /** - * @param string $sql - * @param array $params - * @return int - * @throws Exception - */ - public function execute(string $sql, array $params = []): int - { - $this->_last = time(); - $pdo = $this->_pdo(); - if (!(($prepare = $pdo->prepare($sql)) instanceof PDOStatement)) { - throw new Exception($prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE); - } - if ($prepare->execute($params) === false) { - throw new Exception($prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE); - } - $result = (int)$pdo->lastInsertId(); - $prepare->closeCursor(); - if ($result == 0) { - return true; - } - return $result; - } - - - /** - * @return \PDO - */ - public function _pdo(): \PDO - { - if ($this->_timer === -1) { - $this->heartbeat_check(); - } - if (!($this->pdo instanceof \PDO)) { - $this->pdo = $this->newClient(); - } - return $this->pdo; - } - - - /** - * @return \PDO - */ - private function newClient(): \PDO - { - $link = new \PDO('mysql:dbname=' . $this->dbname . ';host=' . $this->cds, $this->username, $this->password, [ - \PDO::ATTR_EMULATE_PREPARES => false, - \PDO::ATTR_CASE => \PDO::CASE_NATURAL, - \PDO::ATTR_TIMEOUT => $this->connect_timeout, - \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, - \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . $this->charset - ]); - $link->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); - $link->setAttribute(\PDO::ATTR_STRINGIFY_FETCHES, false); - $link->setAttribute(\PDO::ATTR_ORACLE_NULLS, \PDO::NULL_EMPTY_STRING); - if (!empty($this->attributes) && is_array($this->attributes)) { - foreach ($this->attributes as $key => $attribute) { - $link->setAttribute($key, $attribute); - } - } - return $link; - } - -} +dbname = $config['dbname']; + $this->cds = $config['cds']; + $this->username = $config['username']; + $this->password = $config['password']; + $this->connect_timeout = $config['connect_timeout'] ?? 30; + $this->read_timeout = $config['read_timeout'] ?? 10; + $this->charset = $config['charset'] ?? 'utf8mb4'; + $this->attributes = $config['attributes'] ?? []; + } + + + public function init() + { + $this->heartbeat_check(); + } + + + /** + * @return bool + */ + public function inTransaction(): bool + { + return $this->_transaction > 0; + } + + + /** + * + */ + public function heartbeat_check(): void + { + if (env('state', 'start') == 'exit') { + return; + } + if ($this->_timer === -1) { + $this->_timer = Timer::tick(1000, fn() => $this->waite()); + } + } + + + /** + * @throws Exception + */ + private function waite(): void + { + try { + if (env('state', 'start') == 'exit') { + Kiri::getDi()->get(Logger::class)->critical('timer end'); + $this->stopHeartbeatCheck(); + } + if (time() - $this->_last > (int)Config::get('databases.pool.tick', 60)) { + $this->stopHeartbeatCheck(); + $this->pdo = null; + } + } catch (\Throwable $throwable) { + error($throwable); + } + } + + + /** + * + */ + public function stopHeartbeatCheck(): void + { + if ($this->_timer > -1) { + Timer::clear($this->_timer); + } + $this->_timer = -1; + } + + + /** + * + */ + public function beginTransaction() + { + if ($this->_transaction == 0) { + $this->_pdo()->beginTransaction(); + } + $this->_transaction++; + } + + + /** + * + */ + public function commit() + { + if ($this->_transaction == 0) { + $this->_pdo()->commit(); + } + $this->_transaction--; + } + + + /** + * + */ + public function rollback() + { + if ($this->_transaction == 0) { + $this->_pdo()->rollBack(); + } + $this->_transaction--; + } + + + /** + * @param string $sql + * @param array $params + * @return bool|array|null + * @throws Exception + */ + public function fetchAll(string $sql, array $params = []): bool|null|array + { + $pdo = $this->queryPrev($sql, $params); + + $result = $pdo->fetchAll(\PDO::FETCH_ASSOC); + $pdo->closeCursor(); + return $result; + } + + + /** + * @param string $sql + * @param array $params + * @return bool|array|null + * @throws Exception + */ + public function fetch(string $sql, array $params = []): bool|null|array + { + $pdo = $this->queryPrev($sql, $params); + + $result = $pdo->fetch(\PDO::FETCH_ASSOC); + $pdo->closeCursor(); + return $result; + } + + + /** + * @param string $sql + * @param array $params + * @return bool|array|null + * @throws \Exception + */ + public function fetchColumn(string $sql, array $params = []): bool|null|array + { + $pdo = $this->queryPrev($sql, $params); + + $result = $pdo->fetchColumn(\PDO::FETCH_ASSOC); + $pdo->closeCursor(); + return $result; + } + + + /** + * @param string $sql + * @param array $params + * @return int + * @throws Exception + */ + public function count(string $sql, array $params = []): int + { + $pdo = $this->queryPrev($sql, $params); + + $result = $pdo->rowCount(); + $pdo->closeCursor(); + return $result; + } + + + /** + * @param string $sql + * @param array $params + * @return PDOStatement + * @throws Exception + */ + private function queryPrev(string $sql, array $params = []): PDOStatement + { + $this->_last = time(); + try { + if (($statement = $this->_pdo()->query($sql)) === false) { + throw new Exception($this->_pdo()->errorInfo()[1]); + } + return $this->bindValue($statement, $params); + } catch (\PDOException | \Throwable $throwable) { + if (str_contains($throwable->getMessage(), 'MySQL server has gone away')) { + $this->pdo = null; + + return $this->queryPrev($sql, $params); + } + throw new Exception($throwable->getMessage()); + } + } + + + /** + * @param PDOStatement $statement + * @param array $params + * @return PDOStatement + */ + private function bindValue(PDOStatement $statement, array $params = []): PDOStatement + { + if (empty($params)) return $statement; + foreach ($params as $key => $param) { + $statement->bindValue($key, $param); + } + return $statement; + } + + + /** + * @param string $sql + * @param array $params + * @return int + * @throws Exception + */ + public function execute(string $sql, array $params = []): int + { + $this->_last = time(); + $pdo = $this->_pdo(); + if (!(($prepare = $pdo->prepare($sql)) instanceof PDOStatement)) { + throw new Exception($prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE); + } + if ($prepare->execute($params) === false) { + throw new Exception($prepare->errorInfo()[2] ?? static::DB_ERROR_MESSAGE); + } + $result = (int)$pdo->lastInsertId(); + $prepare->closeCursor(); + if ($result == 0) { + return true; + } + return $result; + } + + + /** + * @return \PDO + */ + public function _pdo(): \PDO + { + if ($this->_timer === -1) { + $this->heartbeat_check(); + } + if (!($this->pdo instanceof \PDO)) { + $this->pdo = $this->newClient(); + } + return $this->pdo; + } + + + /** + * @return \PDO + */ + private function newClient(): \PDO + { + $link = new \PDO('mysql:dbname=' . $this->dbname . ';host=' . $this->cds, $this->username, $this->password, [ + \PDO::ATTR_EMULATE_PREPARES => false, + \PDO::ATTR_CASE => \PDO::CASE_NATURAL, + \PDO::ATTR_TIMEOUT => $this->connect_timeout, + \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, + \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . $this->charset + ]); + $link->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + $link->setAttribute(\PDO::ATTR_STRINGIFY_FETCHES, false); + $link->setAttribute(\PDO::ATTR_ORACLE_NULLS, \PDO::NULL_EMPTY_STRING); + if (!empty($this->attributes) && is_array($this->attributes)) { + foreach ($this->attributes as $key => $attribute) { + $link->setAttribute($key, $attribute); + } + } + return $link; + } + +} diff --git a/Mysql/Schema.php b/Mysql/Schema.php index 9cf42f4..9f5ea4e 100644 --- a/Mysql/Schema.php +++ b/Mysql/Schema.php @@ -1,36 +1,36 @@ -_column === null) { - $this->_column = new Columns(['db' => $this->db]); - } - - return $this->_column; - } -} +_column === null) { + $this->_column = new Columns(['db' => $this->db]); + } + + return $this->_column; + } +} diff --git a/Orm/Condition.php b/Orm/Condition.php index 41942c4..2e793b9 100644 --- a/Orm/Condition.php +++ b/Orm/Condition.php @@ -1,29 +1,29 @@ -where($query); - } -} +where($query); + } +} diff --git a/Pagination.php b/Pagination.php index ac720d0..6ebd70c 100644 --- a/Pagination.php +++ b/Pagination.php @@ -1,204 +1,204 @@ -activeQuery = $activeQuery; - } - - - public function clean() - { - unset($this->activeQuery, $this->_callback, $this->_group); - $this->_offset = 0; - $this->_limit = 100; - $this->_max = 0; - $this->_length = 0;; - } - - - /** - * recover class by clone - */ - public function __clone() - { - $this->clean(); - } - - - /** - * @param array|Closure $callback - * @throws Exception - */ - public function setCallback(array|Closure $callback) - { - if (!is_callable($callback, true)) { - throw new Exception('非法回调函数~'); - } - $this->_callback = $callback; - } - - - /** - * @param int $number - * @return Pagination - */ - public function setOffset(int $number): static - { - if ($number < 0) { - $number = 0; - } - $this->_offset = $number; - return $this; - } - - - /** - * @param int $number - * @return Pagination - */ - public function setLimit(int $number): static - { - if ($number < 1) { - $number = 100; - } else if ($number > 5000) { - $number = 5000; - } - $this->_limit = $number; - return $this; - } - - - /** - * @param int $number - * @return Pagination - */ - public function setMax(int $number): static - { - if ($number < 0) { - return $this; - } - $this->_max = $number; - return $this; - } - - - /** - * @param array $param - * @return void - * @throws Exception - */ - public function plunk(array $param = []) - { - $this->loop($param); - } - - - /** - * 轮训 - * @param $param - * @return array - * @throws Exception - */ - public function loop($param): array - { - if ($this->_max > 0 && $this->_length >= $this->_max) { - return $this->output(); - } - [$length, $data] = $this->get(); - - $this->executed($data, $param); - - unset($data); - if ($length < $this->_limit) { - return $this->output(); - } - return $this->loop($param); - } - - - /** - * @return array - */ - public function output(): array - { - return []; - } - - - /** - * @param $data - * @param $param - * @throws Exception - */ - private function executed($data, $param): void - { - try { - call_user_func($this->_callback, $data, $param); - } catch (\Throwable $exception) { - $this->addError($exception, 'throwable'); - } - } - - - /** - * @return array|Collection - */ - private function get(): Collection|array - { - if ($this->_max > 0 && $this->_length + $this->_limit > $this->_max) { - $this->_limit = $this->_length + $this->_limit - $this->_max; - } - $data = $this->activeQuery->limit($this->_offset, $this->_limit)->get(); - $this->_offset += $this->_limit; - - if (is_array($data)) { - $size = count($data); - } else { - $size = $data->size(); - } - $this->_length += $size; - return [$size, $data]; - } - -} +activeQuery = $activeQuery; + } + + + public function clean() + { + unset($this->activeQuery, $this->_callback, $this->_group); + $this->_offset = 0; + $this->_limit = 100; + $this->_max = 0; + $this->_length = 0;; + } + + + /** + * recover class by clone + */ + public function __clone() + { + $this->clean(); + } + + + /** + * @param array|Closure $callback + * @throws Exception + */ + public function setCallback(array|Closure $callback) + { + if (!is_callable($callback, true)) { + throw new Exception('非法回调函数~'); + } + $this->_callback = $callback; + } + + + /** + * @param int $number + * @return Pagination + */ + public function setOffset(int $number): static + { + if ($number < 0) { + $number = 0; + } + $this->_offset = $number; + return $this; + } + + + /** + * @param int $number + * @return Pagination + */ + public function setLimit(int $number): static + { + if ($number < 1) { + $number = 100; + } else if ($number > 5000) { + $number = 5000; + } + $this->_limit = $number; + return $this; + } + + + /** + * @param int $number + * @return Pagination + */ + public function setMax(int $number): static + { + if ($number < 0) { + return $this; + } + $this->_max = $number; + return $this; + } + + + /** + * @param array $param + * @return void + * @throws Exception + */ + public function plunk(array $param = []) + { + $this->loop($param); + } + + + /** + * 轮训 + * @param $param + * @return array + * @throws Exception + */ + public function loop($param): array + { + if ($this->_max > 0 && $this->_length >= $this->_max) { + return $this->output(); + } + [$length, $data] = $this->get(); + + $this->executed($data, $param); + + unset($data); + if ($length < $this->_limit) { + return $this->output(); + } + return $this->loop($param); + } + + + /** + * @return array + */ + public function output(): array + { + return []; + } + + + /** + * @param $data + * @param $param + * @throws Exception + */ + private function executed($data, $param): void + { + try { + call_user_func($this->_callback, $data, $param); + } catch (\Throwable $exception) { + $this->addError($exception, 'throwable'); + } + } + + + /** + * @return array|Collection + */ + private function get(): Collection|array + { + if ($this->_max > 0 && $this->_length + $this->_limit > $this->_max) { + $this->_limit = $this->_length + $this->_limit - $this->_max; + } + $data = $this->activeQuery->limit($this->_offset, $this->_limit)->get(); + $this->_offset += $this->_limit; + + if (is_array($data)) { + $size = count($data); + } else { + $size = $data->size(); + } + $this->_length += $size; + return [$size, $data]; + } + +} diff --git a/Query.php b/Query.php index dcef535..b0c7f79 100644 --- a/Query.php +++ b/Query.php @@ -1,54 +1,54 @@ -builder = SqlBuilder::builder($this); - } - - /** - * @return string - * @throws Exception - */ - public function getSql(): string - { - return $this->builder->get(); - } - - - /** - * @return string - * @throws Exception - */ - public function getCondition(): string - { - return $this->builder->getCondition(); - } - - -} +builder = SqlBuilder::builder($this); + } + + /** + * @return string + * @throws Exception + */ + public function getSql(): string + { + return $this->builder->get(); + } + + + /** + * @return string + * @throws Exception + */ + public function getCondition(): string + { + return $this->builder->getCondition(); + } + + +} diff --git a/Relation.php b/Relation.php index 98f81bc..cee8a27 100644 --- a/Relation.php +++ b/Relation.php @@ -1,111 +1,111 @@ -_query[$identification] = $query; - return $this; - } - - /** - * @param string $name - * @return ActiveQuery|null - */ - public function getQuery(string $name): ?ActiveQuery - { - return $this->_query[$name] ?? null; - } - - - /** - * @param string $identification - * @param $localValue - * @return mixed - * @throws Exception - */ - public function first(string $identification, $localValue): mixed - { - $_identification = $identification . '_first_' . $localValue; - if (isset($this->_relations[$_identification]) && $this->_relations[$_identification] !== null) { - return $this->_relations[$_identification]; - } - - $activeModel = $this->_query[$identification]->first(); - if (empty($activeModel)) { - return null; - } - - return $this->_relations[$_identification] = $activeModel; - } - - - /** - * @param string $identification - * @param $localValue - * @return mixed - * @throws Exception - */ - public function count(string $identification, $localValue): mixed - { - $_identification = $identification . '_count_' . $localValue; - if (isset($this->_relations[$_identification]) && $this->_relations[$_identification] !== null) { - return $this->_relations[$_identification]; - } - - $activeModel = $this->_query[$identification]->count(); - if (empty($activeModel)) { - return null; - } - - return $this->_relations[$_identification] = $activeModel; - } - - - /** - * @param string $identification - * @param $localValue - * @return mixed - */ - public function get(string $identification, $localValue): mixed - { - if (is_array($localValue)) { - $_identification = $identification . '_get_' . implode('_', $localValue); - } else { - $_identification = $identification . '_get_' . $localValue; - } - if (isset($this->_relations[$_identification]) && $this->_relations[$_identification] !== null) { - return $this->_relations[$_identification]; - } - - $activeModel = $this->_query[$identification]->get(); - if (empty($activeModel)) { - return null; - } - - return $this->_relations[$_identification] = $activeModel; - } - -} +_query[$identification] = $query; + return $this; + } + + /** + * @param string $name + * @return ActiveQuery|null + */ + public function getQuery(string $name): ?ActiveQuery + { + return $this->_query[$name] ?? null; + } + + + /** + * @param string $identification + * @param $localValue + * @return mixed + * @throws Exception + */ + public function first(string $identification, $localValue): mixed + { + $_identification = $identification . '_first_' . $localValue; + if (isset($this->_relations[$_identification]) && $this->_relations[$_identification] !== null) { + return $this->_relations[$_identification]; + } + + $activeModel = $this->_query[$identification]->first(); + if (empty($activeModel)) { + return null; + } + + return $this->_relations[$_identification] = $activeModel; + } + + + /** + * @param string $identification + * @param $localValue + * @return mixed + * @throws Exception + */ + public function count(string $identification, $localValue): mixed + { + $_identification = $identification . '_count_' . $localValue; + if (isset($this->_relations[$_identification]) && $this->_relations[$_identification] !== null) { + return $this->_relations[$_identification]; + } + + $activeModel = $this->_query[$identification]->count(); + if (empty($activeModel)) { + return null; + } + + return $this->_relations[$_identification] = $activeModel; + } + + + /** + * @param string $identification + * @param $localValue + * @return mixed + */ + public function get(string $identification, $localValue): mixed + { + if (is_array($localValue)) { + $_identification = $identification . '_get_' . implode('_', $localValue); + } else { + $_identification = $identification . '_get_' . $localValue; + } + if (isset($this->_relations[$_identification]) && $this->_relations[$_identification] !== null) { + return $this->_relations[$_identification]; + } + + $activeModel = $this->_query[$identification]->get(); + if (empty($activeModel)) { + return null; + } + + return $this->_relations[$_identification] = $activeModel; + } + +} diff --git a/SqlBuilder.php b/SqlBuilder.php index 204a176..6610319 100644 --- a/SqlBuilder.php +++ b/SqlBuilder.php @@ -1,375 +1,375 @@ - $query]); - } - - - /** - * @return string - * @throws Exception - */ - public function getCondition(): string - { - return $this->conditionToString(); - } - - - /** - * @param array $compiler - * @return string - * @throws Exception - */ - public function hashCompiler(array $compiler): string - { - return $this->where($compiler); - } - - - /** - * @param array $attributes - * @return bool|array - * @throws Exception - */ - public function update(array $attributes): bool|array - { - [$string, $array] = $this->builderParams($attributes); - - return $this->__updateBuilder($string, $array); - } - - - /** - * @param array $attributes - * @param string $opera - * @return bool|array - * @throws Exception - */ - public function mathematics(array $attributes, string $opera = '+'): bool|array - { - $string = []; - foreach ($attributes as $attribute => $value) { - $string[] = $attribute . '=' . $attribute . $opera . $value; - } - return $this->__updateBuilder($string, []); - } - - - /** - * @param array $string - * @param array $params - * @return array|bool - * @throws Exception - */ - private function __updateBuilder(array $string, array $params): array|bool - { - if (empty($string)) { - return $this->addError('None data update.'); - } - - $condition = $this->conditionToString(); - if (!empty($condition)) { - $condition = ' WHERE ' . $condition; - } - - $update = 'UPDATE ' . $this->tableName() . ' SET ' . implode(',', $string) . $condition; - $update .= $this->builderLimit($this->query, false); - - return [$update, $params]; - } - - - /** - * @param array $attributes - * @param false $isBatch - * @return array - * @throws Exception - */ - public function insert(array $attributes, bool $isBatch = false): array - { - $update = 'INSERT INTO ' . $this->tableName(); - if ($isBatch === false) { - $attributes = [$attributes]; - } - $update .= '(' . implode(',', $this->getFields($attributes)) . ') VALUES '; - - $order = 0; - $keys = $params = []; - foreach ($attributes as $attribute) { - [$_keys, $params] = $this->builderParams($attribute, true, $params, $order); - - $keys[] = implode(',', $_keys); - $order++; - } - return [$update . '(' . implode('),(', $keys) . ')', $params]; - } - - - /** - * @return string - * @throws Exception - */ - public function delete(): string - { - $delete = sprintf('DELETE FROM %s ', $this->query->modelClass->getTable()); - - $this->query->from = null; - - return $delete . ' WHERE ' . $this->_prefix(true); - } - - - /** - * @param $attributes - * @return array - */ - #[Pure] private function getFields($attributes): array - { - return array_keys(current($attributes)); - } - - - /** - * @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 - { - $keys = []; - foreach ($attributes as $key => $value) { - if ($isInsert === true) { - $keys[] = ':' . $key . $order; - $params[$key . $order] = $value; - } else { - [$keys, $params] = $this->resolveParams($key, $value, $order, $params, $keys); - } - } - return [$keys, $params]; - } - - - /** - * @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 - { - if ( - str_starts_with($value, '+ ') || - str_starts_with($value, '- ') - ) { - $keys[] = $key . '=' . $key . ' ' . $value; - } else { - $params[$key . $order] = $value; - $keys[] = $key . '=:' . $key . $order; - } - return [$keys, $params]; - } - - - /** - * @return string - * @throws Exception - */ - public function one(): string - { - $this->query->limit(0, 1); - if (empty($this->query->from) && !empty($this->query->modelClass)) { - $this->query->from($this->query->getTable()); - } - return $this->_prefix(true); - } - - - /** - * @return string - * @throws Exception - */ - public function all(): string - { - if (empty($this->query->from) && !empty($this->query->modelClass)) { - $this->query->from($this->query->getTable()); - } - return $this->_prefix(true); - } - - - /** - * @return string - * @throws Exception - */ - public function count(): string - { - if (empty($this->query->from) && !empty($this->query->modelClass)) { - $this->query->from($this->query->getTable()); - } - return $this->_prefix(false, true); - } - - - /** - * @param $table - * @return string - */ - public function columns($table): string - { - return 'SHOW FULL FIELDS FROM ' . $table; - } - - - /** - * @param bool $hasOrder - * @param bool $isCount - * @return string - * @throws Exception - */ - private function _prefix(bool $hasOrder = false, bool $isCount = false): string - { - $select = ''; - if (!empty($this->query->from)) { - $select = $this->_selectPrefix($isCount); - } - $select = $this->_wherePrefix($select); - if (!empty($this->query->attributes) && is_array($this->query->attributes)) { - $select = strtr($select, $this->query->attributes); - } - - if (!empty($this->query->group)) { - $select .= $this->builderGroup($this->query->group); - } - if ($hasOrder === true && !empty($this->query->order)) { - $select .= $this->builderOrder($this->query->order); - } - $sql = $select . $this->builderLimit($this->query); - if ($this->query->lock) { - $sql .= ' FOR UPDATE'; - } - return $sql; - } - - - /** - * @param $select - * @return string - * @throws Exception - */ - private function _wherePrefix($select): string - { - $condition = $this->conditionToString(); - if (empty($condition)) { - return $select; - } else if (empty($select)) { - return $condition; - } - return sprintf('%s WHERE %s', $select, $condition); - } - - - /** - * @param bool $isCount - * @return string - * @throws Exception - */ - private function _selectPrefix(bool $isCount): string - { - $select = $this->builderSelect($this->query->select, $isCount) . ' FROM ' . $this->tableName(); - if (!empty($this->query->alias)) { - $select .= $this->builderAlias($this->query->alias); - } - if (!empty($this->query->join)) { - $select .= $this->builderJoin($this->query->join); - } - return $select; - } - - - /** - * @param false $isCount - * @return string - * @throws Exception - */ - public function get(bool $isCount = false): string - { - if ($isCount === false) { - return $this->all(); - } - return $this->count(); - } - - - /** - * @return string - * @throws Exception - */ - public function truncate(): string - { - return sprintf('TRUNCATE %s', $this->tableName()); - } - - - /** - * @return string - * @throws Exception - */ - private function conditionToString(): string - { - return $this->where($this->query->where); - } - - - /** - * @return string - * @throws Exception - */ - public function tableName(): string - { - if ($this->query->from instanceof \Closure) { - $this->query->from = sprintf('(%s)', $this->query->makeClosureFunction($this->query->from)); - } - if ($this->query->from instanceof ActiveQuery) { - $this->query->from = sprintf('%s', SqlBuilder::builder($this->query->from)->get($this->query->from)); - } - if (empty($this->query->from)) { - return $this->query->modelClass->getTable(); - } - return $this->query->from; - } - -} + $query]); + } + + + /** + * @return string + * @throws Exception + */ + public function getCondition(): string + { + return $this->conditionToString(); + } + + + /** + * @param array $compiler + * @return string + * @throws Exception + */ + public function hashCompiler(array $compiler): string + { + return $this->where($compiler); + } + + + /** + * @param array $attributes + * @return bool|array + * @throws Exception + */ + public function update(array $attributes): bool|array + { + [$string, $array] = $this->builderParams($attributes); + + return $this->__updateBuilder($string, $array); + } + + + /** + * @param array $attributes + * @param string $opera + * @return bool|array + * @throws Exception + */ + public function mathematics(array $attributes, string $opera = '+'): bool|array + { + $string = []; + foreach ($attributes as $attribute => $value) { + $string[] = $attribute . '=' . $attribute . $opera . $value; + } + return $this->__updateBuilder($string, []); + } + + + /** + * @param array $string + * @param array $params + * @return array|bool + * @throws Exception + */ + private function __updateBuilder(array $string, array $params): array|bool + { + if (empty($string)) { + return $this->addError('None data update.'); + } + + $condition = $this->conditionToString(); + if (!empty($condition)) { + $condition = ' WHERE ' . $condition; + } + + $update = 'UPDATE ' . $this->tableName() . ' SET ' . implode(',', $string) . $condition; + $update .= $this->builderLimit($this->query, false); + + return [$update, $params]; + } + + + /** + * @param array $attributes + * @param false $isBatch + * @return array + * @throws Exception + */ + public function insert(array $attributes, bool $isBatch = false): array + { + $update = 'INSERT INTO ' . $this->tableName(); + if ($isBatch === false) { + $attributes = [$attributes]; + } + $update .= '(' . implode(',', $this->getFields($attributes)) . ') VALUES '; + + $order = 0; + $keys = $params = []; + foreach ($attributes as $attribute) { + [$_keys, $params] = $this->builderParams($attribute, true, $params, $order); + + $keys[] = implode(',', $_keys); + $order++; + } + return [$update . '(' . implode('),(', $keys) . ')', $params]; + } + + + /** + * @return string + * @throws Exception + */ + public function delete(): string + { + $delete = sprintf('DELETE FROM %s ', $this->query->modelClass->getTable()); + + $this->query->from = null; + + return $delete . ' WHERE ' . $this->_prefix(true); + } + + + /** + * @param $attributes + * @return array + */ + #[Pure] private function getFields($attributes): array + { + return array_keys(current($attributes)); + } + + + /** + * @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 + { + $keys = []; + foreach ($attributes as $key => $value) { + if ($isInsert === true) { + $keys[] = ':' . $key . $order; + $params[$key . $order] = $value; + } else { + [$keys, $params] = $this->resolveParams($key, $value, $order, $params, $keys); + } + } + return [$keys, $params]; + } + + + /** + * @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 + { + if ( + str_starts_with($value, '+ ') || + str_starts_with($value, '- ') + ) { + $keys[] = $key . '=' . $key . ' ' . $value; + } else { + $params[$key . $order] = $value; + $keys[] = $key . '=:' . $key . $order; + } + return [$keys, $params]; + } + + + /** + * @return string + * @throws Exception + */ + public function one(): string + { + $this->query->limit(0, 1); + if (empty($this->query->from) && !empty($this->query->modelClass)) { + $this->query->from($this->query->getTable()); + } + return $this->_prefix(true); + } + + + /** + * @return string + * @throws Exception + */ + public function all(): string + { + if (empty($this->query->from) && !empty($this->query->modelClass)) { + $this->query->from($this->query->getTable()); + } + return $this->_prefix(true); + } + + + /** + * @return string + * @throws Exception + */ + public function count(): string + { + if (empty($this->query->from) && !empty($this->query->modelClass)) { + $this->query->from($this->query->getTable()); + } + return $this->_prefix(false, true); + } + + + /** + * @param $table + * @return string + */ + public function columns($table): string + { + return 'SHOW FULL FIELDS FROM ' . $table; + } + + + /** + * @param bool $hasOrder + * @param bool $isCount + * @return string + * @throws Exception + */ + private function _prefix(bool $hasOrder = false, bool $isCount = false): string + { + $select = ''; + if (!empty($this->query->from)) { + $select = $this->_selectPrefix($isCount); + } + $select = $this->_wherePrefix($select); + if (!empty($this->query->attributes) && is_array($this->query->attributes)) { + $select = strtr($select, $this->query->attributes); + } + + if (!empty($this->query->group)) { + $select .= $this->builderGroup($this->query->group); + } + if ($hasOrder === true && !empty($this->query->order)) { + $select .= $this->builderOrder($this->query->order); + } + $sql = $select . $this->builderLimit($this->query); + if ($this->query->lock) { + $sql .= ' FOR UPDATE'; + } + return $sql; + } + + + /** + * @param $select + * @return string + * @throws Exception + */ + private function _wherePrefix($select): string + { + $condition = $this->conditionToString(); + if (empty($condition)) { + return $select; + } else if (empty($select)) { + return $condition; + } + return sprintf('%s WHERE %s', $select, $condition); + } + + + /** + * @param bool $isCount + * @return string + * @throws Exception + */ + private function _selectPrefix(bool $isCount): string + { + $select = $this->builderSelect($this->query->select, $isCount) . ' FROM ' . $this->tableName(); + if (!empty($this->query->alias)) { + $select .= $this->builderAlias($this->query->alias); + } + if (!empty($this->query->join)) { + $select .= $this->builderJoin($this->query->join); + } + return $select; + } + + + /** + * @param false $isCount + * @return string + * @throws Exception + */ + public function get(bool $isCount = false): string + { + if ($isCount === false) { + return $this->all(); + } + return $this->count(); + } + + + /** + * @return string + * @throws Exception + */ + public function truncate(): string + { + return sprintf('TRUNCATE %s', $this->tableName()); + } + + + /** + * @return string + * @throws Exception + */ + private function conditionToString(): string + { + return $this->where($this->query->where); + } + + + /** + * @return string + * @throws Exception + */ + public function tableName(): string + { + if ($this->query->from instanceof \Closure) { + $this->query->from = sprintf('(%s)', $this->query->makeClosureFunction($this->query->from)); + } + if ($this->query->from instanceof ActiveQuery) { + $this->query->from = sprintf('%s', SqlBuilder::builder($this->query->from)->get($this->query->from)); + } + if (empty($this->query->from)) { + return $this->query->modelClass->getTable(); + } + return $this->query->from; + } + +} diff --git a/Traits/Builder.php b/Traits/Builder.php index 0063630..1266aa1 100644 --- a/Traits/Builder.php +++ b/Traits/Builder.php @@ -1,232 +1,232 @@ -toSql() . ')'; - } - return " FROM " . $table; - } - - /** - * @param $join - * @return string - */ - #[Pure] private function builderJoin($join): string - { - if (!empty($join)) { - return ' ' . implode(' ', $join); - } - return ''; - } - - - /** - * @param null $select - * @param bool $isCount - * @return string - */ - #[Pure] private function builderSelect($select = NULL, bool $isCount = false): string - { - if ($isCount) { - return "SELECT COUNT(*)"; - } - if (empty($select)) { - return "SELECT *"; - } - if (is_array($select)) { - return "SELECT " . implode(',', $select); - } else { - return "SELECT " . $select; - } - } - - - /** - * @param $group - * @return string - */ - private function builderGroup($group): string - { - if (empty($group)) { - return ''; - } - return ' GROUP BY ' . $group; - } - - /** - * @param $order - * @return string - */ - #[Pure] private function builderOrder($order): string - { - if (!empty($order)) { - return ' ORDER BY ' . implode(',', $order); - } else { - return ''; - } - } - - /** - * @param ActiveQuery|Query $query - * @param bool $hasLimit - * @return string - */ - #[Pure] private function builderLimit(ActiveQuery|Query $query, bool $hasLimit = true): string - { - if (!is_numeric($query->limit) || $query->limit < 1) { - return ""; - } - if ($query->offset !== null && $hasLimit) { - return ' LIMIT ' . $query->offset . ',' . $query->limit; - } - return ' LIMIT ' . $query->limit; - } - - - /** - * @param $where - * @return string - * @throws Exception - */ - private function where($where): string - { - $_tmp = []; - if (empty($where)) return ''; - if (is_string($where)) return $where; - foreach ($where as $key => $value) { - if (is_null($value)) continue; - - $_value = $this->resolveCondition($key, $value, $_tmp); - - if (empty($_value)) continue; - $_tmp[] = $_value; - } - if (!empty($_tmp)) { - return implode(' AND ', $_tmp); - } - return ''; - } - - - /** - * @param $field - * @param $condition - * @param $_tmp - * @return string - * @throws NotFindClassException - * @throws ReflectionException|Exception - */ - private function resolveCondition($field, $condition, $_tmp): string - { - if (is_string($field)) { - $_value = sprintf('%s = \'%s\'', $field, $condition); - } else if (is_string($condition)) { - $_value = $condition; - } else { - $_value = $this->_arrayMap($condition, $_tmp); - } - return $_value; - } - - - /** - * @param $condition - * @param $array - * @return string - * @throws Exception - */ - private function _arrayMap($condition, $array): string - { - if (!isset($condition[0])) { - return implode(' AND ', $this->_hashMap($condition)); - } - $stroppier = strtoupper($condition[0]); - if (str_contains($stroppier, 'OR')) { - if (!is_string($condition[2])) { - $condition[2] = $this->_hashMap($condition[2]); - } - $builder = Kiri::getDi()->get(OrCondition::class); - $builder->setValue($condition[2]); - $builder->setColumn($condition[1]); - $builder->oldParams = $array; - } else if (isset(ConditionClassMap::$conditionMap[$stroppier])) { - $defaultConfig = ConditionClassMap::$conditionMap[$stroppier]; - - $class = $defaultConfig['class']; - unset($defaultConfig['class']); - - $builder = Kiri::getDi()->make($class, [], $defaultConfig); - $builder->setValue($condition[2]); - $builder->setColumn($condition[1]); - } else { - $builder = Kiri::getDi()->get(HashCondition::class); - $builder->setValue($condition); - } - - $array[] = $builder->builder(); - - return implode(' AND ', $array); - } - - - /** - * @param $condition - * @return array - */ - private function _hashMap($condition): array - { - $_array = []; - foreach ($condition as $key => $value) { - if (is_null($value)) continue; - - $value = is_numeric($value) ? $value : '\'' . $value . '\''; - if (!is_numeric($key)) { - $_array[] = sprintf('%s = %s', $key, $value); - } else { - $_array[] = $value; - } - } - return $_array; - } - - -} +toSql() . ')'; + } + return " FROM " . $table; + } + + /** + * @param $join + * @return string + */ + #[Pure] private function builderJoin($join): string + { + if (!empty($join)) { + return ' ' . implode(' ', $join); + } + return ''; + } + + + /** + * @param null $select + * @param bool $isCount + * @return string + */ + #[Pure] private function builderSelect($select = NULL, bool $isCount = false): string + { + if ($isCount) { + return "SELECT COUNT(*)"; + } + if (empty($select)) { + return "SELECT *"; + } + if (is_array($select)) { + return "SELECT " . implode(',', $select); + } else { + return "SELECT " . $select; + } + } + + + /** + * @param $group + * @return string + */ + private function builderGroup($group): string + { + if (empty($group)) { + return ''; + } + return ' GROUP BY ' . $group; + } + + /** + * @param $order + * @return string + */ + #[Pure] private function builderOrder($order): string + { + if (!empty($order)) { + return ' ORDER BY ' . implode(',', $order); + } else { + return ''; + } + } + + /** + * @param ActiveQuery|Query $query + * @param bool $hasLimit + * @return string + */ + #[Pure] private function builderLimit(ActiveQuery|Query $query, bool $hasLimit = true): string + { + if (!is_numeric($query->limit) || $query->limit < 1) { + return ""; + } + if ($query->offset !== null && $hasLimit) { + return ' LIMIT ' . $query->offset . ',' . $query->limit; + } + return ' LIMIT ' . $query->limit; + } + + + /** + * @param $where + * @return string + * @throws Exception + */ + private function where($where): string + { + $_tmp = []; + if (empty($where)) return ''; + if (is_string($where)) return $where; + foreach ($where as $key => $value) { + if (is_null($value)) continue; + + $_value = $this->resolveCondition($key, $value, $_tmp); + + if (empty($_value)) continue; + $_tmp[] = $_value; + } + if (!empty($_tmp)) { + return implode(' AND ', $_tmp); + } + return ''; + } + + + /** + * @param $field + * @param $condition + * @param $_tmp + * @return string + * @throws NotFindClassException + * @throws ReflectionException|Exception + */ + private function resolveCondition($field, $condition, $_tmp): string + { + if (is_string($field)) { + $_value = sprintf('%s = \'%s\'', $field, $condition); + } else if (is_string($condition)) { + $_value = $condition; + } else { + $_value = $this->_arrayMap($condition, $_tmp); + } + return $_value; + } + + + /** + * @param $condition + * @param $array + * @return string + * @throws Exception + */ + private function _arrayMap($condition, $array): string + { + if (!isset($condition[0])) { + return implode(' AND ', $this->_hashMap($condition)); + } + $stroppier = strtoupper($condition[0]); + if (str_contains($stroppier, 'OR')) { + if (!is_string($condition[2])) { + $condition[2] = $this->_hashMap($condition[2]); + } + $builder = Kiri::getDi()->get(OrCondition::class); + $builder->setValue($condition[2]); + $builder->setColumn($condition[1]); + $builder->oldParams = $array; + } else if (isset(ConditionClassMap::$conditionMap[$stroppier])) { + $defaultConfig = ConditionClassMap::$conditionMap[$stroppier]; + + $class = $defaultConfig['class']; + unset($defaultConfig['class']); + + $builder = Kiri::getDi()->make($class, [], $defaultConfig); + $builder->setValue($condition[2]); + $builder->setColumn($condition[1]); + } else { + $builder = Kiri::getDi()->get(HashCondition::class); + $builder->setValue($condition); + } + + $array[] = $builder->builder(); + + return implode(' AND ', $array); + } + + + /** + * @param $condition + * @return array + */ + private function _hashMap($condition): array + { + $_array = []; + foreach ($condition as $key => $value) { + if (is_null($value)) continue; + + $value = is_numeric($value) ? $value : '\'' . $value . '\''; + if (!is_numeric($key)) { + $_array[] = sprintf('%s = %s', $key, $value); + } else { + $_array[] = $value; + } + } + return $_array; + } + + +} diff --git a/Traits/HasBase.php b/Traits/HasBase.php index 0b874e8..bf28bd9 100644 --- a/Traits/HasBase.php +++ b/Traits/HasBase.php @@ -1,81 +1,81 @@ -whereIn($primaryId, $value); - } else { - $_model = $model::query()->where(['t1.' . $primaryId => $value]); - } - - $this->_relation = $relation->bindIdentification($model, $_model); - - $this->model = $model; - $this->value = $value; - } - - - /** - * @param $name - * @return mixed - */ - public function __get($name): mixed - { - if (empty($this->value)) { - return null; - } - return $this->get(); - } -} +whereIn($primaryId, $value); + } else { + $_model = $model::query()->where(['t1.' . $primaryId => $value]); + } + + $this->_relation = $relation->bindIdentification($model, $_model); + + $this->model = $model; + $this->value = $value; + } + + + /** + * @param $name + * @return mixed + */ + public function __get($name): mixed + { + if (empty($this->value)) { + return null; + } + return $this->get(); + } +} diff --git a/Traits/QueryTrait.php b/Traits/QueryTrait.php index f6a3674..30a4200 100644 --- a/Traits/QueryTrait.php +++ b/Traits/QueryTrait.php @@ -1,963 +1,963 @@ -where = []; - $this->select = []; - $this->join = []; - $this->order = []; - $this->offset = NULL; - $this->limit = NULL; - $this->group = ''; - $this->from = ''; - $this->alias = 't1'; - $this->filter = []; - } - - - /** - * @param string $column - * @param callable $callable - * @return $this - */ - public function when(string $column, callable $callable): static - { - $caseWhen = new When($column, $this); - - call_user_func($callable, $caseWhen); - - $this->where[] = $caseWhen->end(); - - return $this; - } - - - /** - * @param bool $lock - * @return $this - */ - public function lock(bool $lock): static - { - $this->lock = $lock; - return $this; - } - - - /** - * @param string $whereRaw - * @return QueryTrait - */ - public function whereRaw(string $whereRaw): static - { - if (empty($whereRaw)) { - return $this; - } - $this->where[] = $whereRaw; - return $this; - } - - - /** - * @param string|array|Closure $condition - * @param string|array|Closure $condition1 - * @param string|array|Closure $condition2 - * @return $this - * @throws NotFindClassException - * @throws ReflectionException - */ - 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 - * @return $this - */ - public function ifNotWhere($bool): static - { - $this->ifNotWhere = $bool; - return $this; - } - - /** - * @return string - * @throws Exception - */ - public function getTable(): string - { - return $this->modelClass->getTable(); - } - - - /** - * @param string $column - * @param string $value - * @return $this - */ - public function whereLocate(string $column, string $value): static - { - $this->where[] = 'LOCATE(' . $column . ',\'' . addslashes($value) . '\') > 0'; - return $this; - } - - - /** - * @param string $column - * @return $this - */ - public function whereNull(string $column): static - { - $this->where[] = $column . ' IS NULL'; - return $this; - } - - - /** - * @param string $column - * @return $this - */ - public function whereEmpty(string $column): static - { - $this->where[] = $column . ' = \'\''; - return $this; - } - - /** - * @param string $column - * @return $this - */ - public function whereAnnotationmpty(string $column): static - { - $this->where[] = $column . ' <> \'\''; - return $this; - } - - /** - * @param string $column - * @return $this - */ - public function whereNotNull(string $column): static - { - $this->where[] = $column . ' IS NOT NULL'; - 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 - * - * @return $this - * - * select * from tableName as t1 - */ - public function alias(string $alias = 't1'): static - { - $this->alias = $alias; - return $this; - } - - /** - * @param string|Closure $tableName - * - * @return $this - */ - public function from(string|Closure $tableName): static - { - $this->from = $tableName; - return $this; - } - - /** - * @param string $tableName - * @param string $alias - * @param null $on - * @param array|null $param - * @return $this - * $query->join([$tableName, ['userId'=>'uuvOd']], $param) - * $query->join([$tableName, ['userId'=>'uuvOd'], $param]) - * $query->join($tableName, ['userId'=>'uuvOd',$param]) - */ - private function join(string $tableName, string $alias, $on = NULL, array $param = NULL): static - { - if (empty($on)) { - return $this; - } - $join[] = $tableName . ' AS ' . $alias; - $join[] = 'ON ' . $this->onCondition($alias, $on); - if (empty($join)) { - return $this; - } - - $this->join[] = implode(' ', $join); - if (!empty($param)) { - $this->addParams($param); - } - - return $this; - } - - /** - * @param $alias - * @param $on - * @return string - */ - private function onCondition($alias, $on): string - { - $array = []; - foreach ($on as $key => $item) { - if (!str_contains($item, '.')) { - $this->addParam($key, $item); - } else { - $explode = explode('.', $item); - if (isset($explode[1]) && ($explode[0] == $alias || $this->alias == $explode[0])) { - $array[] = $key . '=' . $item; - } else { - $this->addParam($key, $item); - } - } - } - return implode(' AND ', $array); - } - - /** - * @param string $tableName - * @param string $alias - * @param $onCondition - * @param null $param - * @return $this - * @throws Exception - */ - public function leftJoin(string $tableName, string $alias, $onCondition, $param = NULL): static - { - if (class_exists($tableName)) { - $model = Kiri::getDi()->get($tableName); - if (!($model instanceof ModelInterface)) { - throw new Exception('Model must implement ' . ModelInterface::class); - } - $tableName = $model->getTable(); - } - return $this->join(...["LEFT JOIN " . $tableName, $alias, $onCondition, $param]); - } - - /** - * @param $tableName - * @param $alias - * @param $onCondition - * @param null $param - * @return $this - * @throws Exception - */ - public function rightJoin($tableName, $alias, $onCondition, $param = NULL): static - { - if (class_exists($tableName)) { - $model = Kiri::getDi()->get($tableName); - if (!($model instanceof ModelInterface)) { - throw new Exception('Model must implement ' . ModelInterface::class); - } - $tableName = $model->getTable(); - } - return $this->join(...["RIGHT JOIN " . $tableName, $alias, $onCondition, $param]); - } - - /** - * @param $tableName - * @param $alias - * @param $onCondition - * @param null $param - * @return $this - * @throws Exception - */ - public function innerJoin($tableName, $alias, $onCondition, $param = NULL): static - { - if (class_exists($tableName)) { - $model = Kiri::getDi()->get($tableName); - if (!($model instanceof ModelInterface)) { - throw new Exception('Model must implement ' . ModelInterface::class); - } - $tableName = $model->getTable(); - } - return $this->join(...["INNER JOIN " . $tableName, $alias, $onCondition, $param]); - } - - /** - * @param $array - * - * @return string - */ - private function toString($array): string - { - $tmp = []; - if (!is_array($array)) { - return $array; - } - foreach ($array as $key => $val) { - if (is_array($val)) { - $tmp[] = $this->toString($array); - } else { - $tmp[] = $key . '=:' . $key; - $this->attributes[':' . $key] = $val; - } - } - return implode(' AND ', $tmp); - } - - /** - * @param string $field - * - * @return $this - */ - public function sum(string $field): static - { - $this->select[] = 'SUM(' . $field . ') AS ' . $field; - return $this; - } - - /** - * @param string $field - * @return $this - */ - public function max(string $field): static - { - $this->select[] = 'MAX(' . $field . ') AS ' . $field; - return $this; - } - - /** - * @param string $lngField - * @param string $latField - * @param int $lng1 - * @param int $lat1 - * - * @return $this - */ - public function distance(string $lngField, string $latField, int $lng1, int $lat1): static - { - $sql = "ROUND(6378.138 * 2 * ASIN(SQRT(POW(SIN(($lat1 * PI() / 180 - $lat1 * PI() / 180) / 2),2) + COS($lat1 * PI() / 180) * COS($latField * PI() / 180) * POW(SIN(($lng1 * PI() / 180 - $lngField * PI() / 180) / 2),2))) * 1000) AS distance"; - $this->select[] = $sql; - return $this; - } - - /** - * @param string|array $column - * @param string $sort - * - * @return $this - * - * [ - * 'addTime', - * 'descTime desc' - * ] - */ - public function orderBy(string|array $column, string $sort = 'DESC'): static - { - if (empty($column)) { - return $this; - } - if (is_string($column)) { - return $this->addOrder(...func_get_args()); - } - - foreach ($column as $key => $val) { - $this->addOrder($val); - } - - return $this; - } - - /** - * @param string $column - * @param string $sort - * - * @return $this - * - */ - private function addOrder(string $column, string $sort = 'DESC'): static - { - $column = trim($column); - - if (func_num_args() == 1 || str_contains($column, ' ')) { - $this->order[] = $column; - } else { - $this->order[] = "$column $sort"; - } - return $this; - } - - /** - * @param array|string $column - * - * @return $this - */ - public function select(array|string $column = '*'): static - { - if ($column == '*') { - $this->select = $column; - } else { - if (!is_array($column)) { - $column = explode(',', $column); - } - foreach ($column as $val) { - $this->select[] = $val; - } - } - return $this; - } - - /** - * @return $this - */ - public function orderRand(): static - { - $this->order[] = 'RAND()'; - return $this; - } - - /** - * @param array|Closure|string $conditionArray - * @param string $opera - * @param null $value - * @return QueryTrait - * @throws NotFindClassException - * @throws ReflectionException - */ - public function whereOr(array|Closure|string $conditionArray = [], string $opera = '=', $value = null): static - { - if ($conditionArray instanceof Closure) { - $conditionArray = $this->makeClosureFunction($conditionArray); - } - - if (func_num_args() > 1) { - [$conditionArray, $opera, $value] = $this->opera(...func_get_args()); - - $conditionArray = $this->sprintf($conditionArray, $value, $opera); - } - - $this->where = ['((' . implode(' AND ', $this->where) . ') OR (' . $conditionArray . '))']; - return $this; - } - - /** - * @param string $columns - * @param string|int|bool|null $value - * - * @param string $opera - * @return QueryTrait - */ - public function whereAnd(string $columns, string $opera = '=', string|int|null|bool $value = NULL): static - { - [$columns, $opera, $value] = $this->opera(...func_get_args()); - - $this->where[] = $this->sprintf($columns, $value, $opera); - return $this; - } - - - /** - * @param string $columns - * @param string $value - * @return $this - * @throws Exception - */ - public function whereLike(string $columns, string $value): static - { - if (empty($columns) || (empty($value) && $value != 0)) { - return $this; - } - - if (is_array($columns)) { - $columns = 'CONCAT(' . implode(',^,', $columns) . ')'; - } - - $this->where[] = $columns . ' LIKE \'%' . addslashes($value) . '%\''; - - return $this; - } - - /** - * @param string $columns - * @param string $value - * @return $this - * @throws Exception - */ - public function whereLeftLike(string $columns, string $value): static - { - if (empty($columns) || (empty($value) && $value != 0)) { - return $this; - } - - if (is_array($columns)) { - $columns = 'CONCAT(' . implode(',^,', $columns) . ')'; - } - - $this->where[] = $columns . ' LLike \'%' . addslashes($value) . '\''; - - return $this; - } - - /** - * @param string $columns - * @param string $value - * @return $this - * @throws Exception - */ - public function whereRightLike(string $columns, string $value): static - { - if (empty($columns) || (empty($value) && $value != 0)) { - return $this; - } - - if (is_array($columns)) { - $columns = 'CONCAT(' . implode(',^,', $columns) . ')'; - } - - $this->where[] = $columns . ' RLike \'' . addslashes($value) . '%\''; - - return $this; - } - - - /** - * @param string $columns - * @param string $value - * @return $this - * @throws Exception - */ - public function whereNotLike(string $columns, string $value): static - { - if (empty($columns) || (empty($value) && $value != 0)) { - return $this; - } - - if (is_array($columns)) { - $columns = 'CONCAT(' . implode(',^,', $columns) . ')'; - } - - $this->where[] = $columns . ' NOT LIKE \'%' . addslashes($value) . '%\''; - - return $this; - } - - /** - * @param string $column - * @param int $value - * @return $this - * @throws Exception - * @see MathematicsCondition - */ - public function whereEq(string $column, int $value): static - { - $this->where[] = ['EQ', $column, $value]; - - return $this; - } - - - /** - * @param string $column - * @param int $value - * @return $this - * @throws Exception - * @see MathematicsCondition - */ - public function whereNeq(string $column, int $value): static - { - $this->where[] = ['NEQ', $column, $value]; - - return $this; - } - - - /** - * @param string $column - * @param int $value - * @return $this - * @throws Exception - * @see MathematicsCondition - */ - public function whereGt(string $column, int $value): static - { - $this->where[] = ['GT', $column, $value]; - - return $this; - } - - /** - * @param string $column - * @param int $value - * @return $this - * @throws Exception - * @see MathematicsCondition - */ - public function whereEgt(string $column, int $value): static - { - $this->where[] = ['EGT', $column, $value]; - - return $this; - } - - - /** - * @param string $column - * @param int $value - * @return $this - * @throws Exception - * @see MathematicsCondition - */ - public function whereLt(string $column, int $value): static - { - $this->where[] = ['LT', $column, $value]; - - return $this; - } - - /** - * @param string $column - * @param int $value - * @return $this - * @throws Exception - * @see MathematicsCondition - */ - public function whereElt(string $column, int $value): static - { - $this->where[] = ['ELT', $column, $value]; - - return $this; - } - - /** - * @param string $columns - * @param array|Closure $value - * @return $this - * @throws NotFindClassException - * @throws ReflectionException - */ - public function whereIn(string $columns, array|Closure $value): static - { - if ($value instanceof Closure) { - $value = $this->makeClosureFunction($value); - } - if (empty($value)) { - $value = [-1]; - } - $this->where[] = ['IN', $columns, $value]; - return $this; - } - - - /** - * @param $value - * @return ActiveQuery - * @throws Exception - */ - public function makeNewQuery($value): ActiveQuery - { - $activeQuery = new ActiveQuery($this->modelClass); - call_user_func($value, $activeQuery); - if (empty($activeQuery->from)) { - $activeQuery->from($activeQuery->modelClass->getTable()); - } - return $activeQuery; - } - - - /** - * @return Query - * @throws ReflectionException - * @throws NotFindClassException - */ - public function makeNewSqlGenerate(): Query - { - return Kiri::createObject(['class' => Query::class]); - } - - - /** - * @param string $columns - * @param array $value - * @return $this - */ - public function whereNotIn(string $columns, array $value): static - { - if (empty($value) || !is_array($value)) { - $value = [-1]; - } - $this->where[] = ['NOT IN', $columns, $value]; - return $this; - } - - /** - * @param string $column - * @param int $start - * @param int $end - * @return $this - */ - public function whereBetween(string $column, int $start, int $end): static - { - if (empty($column) || empty($start) || empty($end)) { - return $this; - } - - $this->where[] = $column . ' BETWEEN ' . $start . ' AND ' . $end; - - return $this; - } - - /** - * @param string $column - * @param int $start - * @param int $end - * @return $this - */ - public function whereNotBetween(string $column, int $start, int $end): static - { - if (empty($column) || empty($start) || empty($end)) { - return $this; - } - - $this->where[] = $column . 'NOT BETWEEN' . $start . ' AND ' . $end; - - return $this; - } - - /** - * @param array $params - * - * @return $this - */ - public function bindParams(array $params = []): static - { - if (empty($params)) { - return $this; - } - $this->attributes = $params; - return $this; - } - - /** - * @param Closure|array|string $column - * @param string $opera - * @param null $value - * @return $this - * @throws NotFindClassException - * @throws ReflectionException - */ - public function where(Closure|array|string $column, string $opera = '=', $value = null): static - { - if (is_array($column)) { - return $this->addArray($column); - } - if ($column instanceof Closure) { - $this->where[] = $this->makeClosureFunction($column); - return $this; - } - if (is_string($column)) { - $this->where[] = $column; - } else { - [$column, $opera, $value] = $this->opera(...func_get_args()); - $this->where[] = "$column $opera $value"; - } - return $this; - } - - - /** - * @param Closure|array $closure - * @return string - * @throws NotFindClassException - * @throws ReflectionException - * @throws Exception - */ - public function makeClosureFunction(Closure|array $closure): string - { - $generate = $this->makeNewSqlGenerate(); - if ($closure instanceof Closure) { - call_user_func($closure, $generate); - } else { - $generate->where($closure); - } - return $generate->getSql(); - } - - - /** - * @param string $name - * @param string|null $having - * - * @return $this - */ - public function groupBy(string $name, string $having = NULL): static - { - $this->group = $name; - if (empty($having)) { - return $this; - } - $this->group .= ' HAVING ' . $having; - return $this; - } - - /** - * @param int $offset - * @param int $limit - * - * @return $this - */ - public function limit(int $offset, int $limit = 20): static - { - $this->offset = $offset; - $this->limit = $limit; - return $this; - } - - - /** - * @return array - */ - private function opera(): array - { - if (func_num_args() == 3) { - [$column, $opera, $value] = func_get_args(); - } else { - [$column, $value] = func_get_args(); - } - if (!isset($opera)) { - $opera = '='; - } - return [$column, $opera, $value]; - } - - - /** - * @param array $array - * @return $this - */ - private function addArray(array $array): static - { - foreach ($array as $key => $value) { - if (is_null($value)) continue; - if (is_numeric($key)) { - [$column, $opera, $value] = $this->opera(...$value); - - $this->where[] = $this->sprintf($column, $value, $opera); - } else { - $this->where[] = $this->sprintf($key, $value); - } - } - return $this; - } - - - /** - * @param $column - * @param $value - * @param string $opera - * @return string - */ - private function sprintf($column, $value, string $opera = '='): string - { - if (is_string($value)) { - $value = trim($value, '\'"'); - } - return "$column $opera '$value'"; - } - - - /** - * @return $this - */ - public function oneLimit(): static - { - $this->limit = 1; - return $this; - } - -} +where = []; + $this->select = []; + $this->join = []; + $this->order = []; + $this->offset = NULL; + $this->limit = NULL; + $this->group = ''; + $this->from = ''; + $this->alias = 't1'; + $this->filter = []; + } + + + /** + * @param string $column + * @param callable $callable + * @return $this + */ + public function when(string $column, callable $callable): static + { + $caseWhen = new When($column, $this); + + call_user_func($callable, $caseWhen); + + $this->where[] = $caseWhen->end(); + + return $this; + } + + + /** + * @param bool $lock + * @return $this + */ + public function lock(bool $lock): static + { + $this->lock = $lock; + return $this; + } + + + /** + * @param string $whereRaw + * @return QueryTrait + */ + public function whereRaw(string $whereRaw): static + { + if (empty($whereRaw)) { + return $this; + } + $this->where[] = $whereRaw; + return $this; + } + + + /** + * @param string|array|Closure $condition + * @param string|array|Closure $condition1 + * @param string|array|Closure $condition2 + * @return $this + * @throws NotFindClassException + * @throws ReflectionException + */ + 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 + * @return $this + */ + public function ifNotWhere($bool): static + { + $this->ifNotWhere = $bool; + return $this; + } + + /** + * @return string + * @throws Exception + */ + public function getTable(): string + { + return $this->modelClass->getTable(); + } + + + /** + * @param string $column + * @param string $value + * @return $this + */ + public function whereLocate(string $column, string $value): static + { + $this->where[] = 'LOCATE(' . $column . ',\'' . addslashes($value) . '\') > 0'; + return $this; + } + + + /** + * @param string $column + * @return $this + */ + public function whereNull(string $column): static + { + $this->where[] = $column . ' IS NULL'; + return $this; + } + + + /** + * @param string $column + * @return $this + */ + public function whereEmpty(string $column): static + { + $this->where[] = $column . ' = \'\''; + return $this; + } + + /** + * @param string $column + * @return $this + */ + public function whereAnnotationmpty(string $column): static + { + $this->where[] = $column . ' <> \'\''; + return $this; + } + + /** + * @param string $column + * @return $this + */ + public function whereNotNull(string $column): static + { + $this->where[] = $column . ' IS NOT NULL'; + 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 + * + * @return $this + * + * select * from tableName as t1 + */ + public function alias(string $alias = 't1'): static + { + $this->alias = $alias; + return $this; + } + + /** + * @param string|Closure $tableName + * + * @return $this + */ + public function from(string|Closure $tableName): static + { + $this->from = $tableName; + return $this; + } + + /** + * @param string $tableName + * @param string $alias + * @param null $on + * @param array|null $param + * @return $this + * $query->join([$tableName, ['userId'=>'uuvOd']], $param) + * $query->join([$tableName, ['userId'=>'uuvOd'], $param]) + * $query->join($tableName, ['userId'=>'uuvOd',$param]) + */ + private function join(string $tableName, string $alias, $on = NULL, array $param = NULL): static + { + if (empty($on)) { + return $this; + } + $join[] = $tableName . ' AS ' . $alias; + $join[] = 'ON ' . $this->onCondition($alias, $on); + if (empty($join)) { + return $this; + } + + $this->join[] = implode(' ', $join); + if (!empty($param)) { + $this->addParams($param); + } + + return $this; + } + + /** + * @param $alias + * @param $on + * @return string + */ + private function onCondition($alias, $on): string + { + $array = []; + foreach ($on as $key => $item) { + if (!str_contains($item, '.')) { + $this->addParam($key, $item); + } else { + $explode = explode('.', $item); + if (isset($explode[1]) && ($explode[0] == $alias || $this->alias == $explode[0])) { + $array[] = $key . '=' . $item; + } else { + $this->addParam($key, $item); + } + } + } + return implode(' AND ', $array); + } + + /** + * @param string $tableName + * @param string $alias + * @param $onCondition + * @param null $param + * @return $this + * @throws Exception + */ + public function leftJoin(string $tableName, string $alias, $onCondition, $param = NULL): static + { + if (class_exists($tableName)) { + $model = Kiri::getDi()->get($tableName); + if (!($model instanceof ModelInterface)) { + throw new Exception('Model must implement ' . ModelInterface::class); + } + $tableName = $model->getTable(); + } + return $this->join(...["LEFT JOIN " . $tableName, $alias, $onCondition, $param]); + } + + /** + * @param $tableName + * @param $alias + * @param $onCondition + * @param null $param + * @return $this + * @throws Exception + */ + public function rightJoin($tableName, $alias, $onCondition, $param = NULL): static + { + if (class_exists($tableName)) { + $model = Kiri::getDi()->get($tableName); + if (!($model instanceof ModelInterface)) { + throw new Exception('Model must implement ' . ModelInterface::class); + } + $tableName = $model->getTable(); + } + return $this->join(...["RIGHT JOIN " . $tableName, $alias, $onCondition, $param]); + } + + /** + * @param $tableName + * @param $alias + * @param $onCondition + * @param null $param + * @return $this + * @throws Exception + */ + public function innerJoin($tableName, $alias, $onCondition, $param = NULL): static + { + if (class_exists($tableName)) { + $model = Kiri::getDi()->get($tableName); + if (!($model instanceof ModelInterface)) { + throw new Exception('Model must implement ' . ModelInterface::class); + } + $tableName = $model->getTable(); + } + return $this->join(...["INNER JOIN " . $tableName, $alias, $onCondition, $param]); + } + + /** + * @param $array + * + * @return string + */ + private function toString($array): string + { + $tmp = []; + if (!is_array($array)) { + return $array; + } + foreach ($array as $key => $val) { + if (is_array($val)) { + $tmp[] = $this->toString($array); + } else { + $tmp[] = $key . '=:' . $key; + $this->attributes[':' . $key] = $val; + } + } + return implode(' AND ', $tmp); + } + + /** + * @param string $field + * + * @return $this + */ + public function sum(string $field): static + { + $this->select[] = 'SUM(' . $field . ') AS ' . $field; + return $this; + } + + /** + * @param string $field + * @return $this + */ + public function max(string $field): static + { + $this->select[] = 'MAX(' . $field . ') AS ' . $field; + return $this; + } + + /** + * @param string $lngField + * @param string $latField + * @param int $lng1 + * @param int $lat1 + * + * @return $this + */ + public function distance(string $lngField, string $latField, int $lng1, int $lat1): static + { + $sql = "ROUND(6378.138 * 2 * ASIN(SQRT(POW(SIN(($lat1 * PI() / 180 - $lat1 * PI() / 180) / 2),2) + COS($lat1 * PI() / 180) * COS($latField * PI() / 180) * POW(SIN(($lng1 * PI() / 180 - $lngField * PI() / 180) / 2),2))) * 1000) AS distance"; + $this->select[] = $sql; + return $this; + } + + /** + * @param string|array $column + * @param string $sort + * + * @return $this + * + * [ + * 'addTime', + * 'descTime desc' + * ] + */ + public function orderBy(string|array $column, string $sort = 'DESC'): static + { + if (empty($column)) { + return $this; + } + if (is_string($column)) { + return $this->addOrder(...func_get_args()); + } + + foreach ($column as $key => $val) { + $this->addOrder($val); + } + + return $this; + } + + /** + * @param string $column + * @param string $sort + * + * @return $this + * + */ + private function addOrder(string $column, string $sort = 'DESC'): static + { + $column = trim($column); + + if (func_num_args() == 1 || str_contains($column, ' ')) { + $this->order[] = $column; + } else { + $this->order[] = "$column $sort"; + } + return $this; + } + + /** + * @param array|string $column + * + * @return $this + */ + public function select(array|string $column = '*'): static + { + if ($column == '*') { + $this->select = $column; + } else { + if (!is_array($column)) { + $column = explode(',', $column); + } + foreach ($column as $val) { + $this->select[] = $val; + } + } + return $this; + } + + /** + * @return $this + */ + public function orderRand(): static + { + $this->order[] = 'RAND()'; + return $this; + } + + /** + * @param array|Closure|string $conditionArray + * @param string $opera + * @param null $value + * @return QueryTrait + * @throws NotFindClassException + * @throws ReflectionException + */ + public function whereOr(array|Closure|string $conditionArray = [], string $opera = '=', $value = null): static + { + if ($conditionArray instanceof Closure) { + $conditionArray = $this->makeClosureFunction($conditionArray); + } + + if (func_num_args() > 1) { + [$conditionArray, $opera, $value] = $this->opera(...func_get_args()); + + $conditionArray = $this->sprintf($conditionArray, $value, $opera); + } + + $this->where = ['((' . implode(' AND ', $this->where) . ') OR (' . $conditionArray . '))']; + return $this; + } + + /** + * @param string $columns + * @param string|int|bool|null $value + * + * @param string $opera + * @return QueryTrait + */ + public function whereAnd(string $columns, string $opera = '=', string|int|null|bool $value = NULL): static + { + [$columns, $opera, $value] = $this->opera(...func_get_args()); + + $this->where[] = $this->sprintf($columns, $value, $opera); + return $this; + } + + + /** + * @param string $columns + * @param string $value + * @return $this + * @throws Exception + */ + public function whereLike(string $columns, string $value): static + { + if (empty($columns) || (empty($value) && $value != 0)) { + return $this; + } + + if (is_array($columns)) { + $columns = 'CONCAT(' . implode(',^,', $columns) . ')'; + } + + $this->where[] = $columns . ' LIKE \'%' . addslashes($value) . '%\''; + + return $this; + } + + /** + * @param string $columns + * @param string $value + * @return $this + * @throws Exception + */ + public function whereLeftLike(string $columns, string $value): static + { + if (empty($columns) || (empty($value) && $value != 0)) { + return $this; + } + + if (is_array($columns)) { + $columns = 'CONCAT(' . implode(',^,', $columns) . ')'; + } + + $this->where[] = $columns . ' LLike \'%' . addslashes($value) . '\''; + + return $this; + } + + /** + * @param string $columns + * @param string $value + * @return $this + * @throws Exception + */ + public function whereRightLike(string $columns, string $value): static + { + if (empty($columns) || (empty($value) && $value != 0)) { + return $this; + } + + if (is_array($columns)) { + $columns = 'CONCAT(' . implode(',^,', $columns) . ')'; + } + + $this->where[] = $columns . ' RLike \'' . addslashes($value) . '%\''; + + return $this; + } + + + /** + * @param string $columns + * @param string $value + * @return $this + * @throws Exception + */ + public function whereNotLike(string $columns, string $value): static + { + if (empty($columns) || (empty($value) && $value != 0)) { + return $this; + } + + if (is_array($columns)) { + $columns = 'CONCAT(' . implode(',^,', $columns) . ')'; + } + + $this->where[] = $columns . ' NOT LIKE \'%' . addslashes($value) . '%\''; + + return $this; + } + + /** + * @param string $column + * @param int $value + * @return $this + * @throws Exception + * @see MathematicsCondition + */ + public function whereEq(string $column, int $value): static + { + $this->where[] = ['EQ', $column, $value]; + + return $this; + } + + + /** + * @param string $column + * @param int $value + * @return $this + * @throws Exception + * @see MathematicsCondition + */ + public function whereNeq(string $column, int $value): static + { + $this->where[] = ['NEQ', $column, $value]; + + return $this; + } + + + /** + * @param string $column + * @param int $value + * @return $this + * @throws Exception + * @see MathematicsCondition + */ + public function whereGt(string $column, int $value): static + { + $this->where[] = ['GT', $column, $value]; + + return $this; + } + + /** + * @param string $column + * @param int $value + * @return $this + * @throws Exception + * @see MathematicsCondition + */ + public function whereEgt(string $column, int $value): static + { + $this->where[] = ['EGT', $column, $value]; + + return $this; + } + + + /** + * @param string $column + * @param int $value + * @return $this + * @throws Exception + * @see MathematicsCondition + */ + public function whereLt(string $column, int $value): static + { + $this->where[] = ['LT', $column, $value]; + + return $this; + } + + /** + * @param string $column + * @param int $value + * @return $this + * @throws Exception + * @see MathematicsCondition + */ + public function whereElt(string $column, int $value): static + { + $this->where[] = ['ELT', $column, $value]; + + return $this; + } + + /** + * @param string $columns + * @param array|Closure $value + * @return $this + * @throws NotFindClassException + * @throws ReflectionException + */ + public function whereIn(string $columns, array|Closure $value): static + { + if ($value instanceof Closure) { + $value = $this->makeClosureFunction($value); + } + if (empty($value)) { + $value = [-1]; + } + $this->where[] = ['IN', $columns, $value]; + return $this; + } + + + /** + * @param $value + * @return ActiveQuery + * @throws Exception + */ + public function makeNewQuery($value): ActiveQuery + { + $activeQuery = new ActiveQuery($this->modelClass); + call_user_func($value, $activeQuery); + if (empty($activeQuery->from)) { + $activeQuery->from($activeQuery->modelClass->getTable()); + } + return $activeQuery; + } + + + /** + * @return Query + * @throws ReflectionException + * @throws NotFindClassException + */ + public function makeNewSqlGenerate(): Query + { + return Kiri::createObject(['class' => Query::class]); + } + + + /** + * @param string $columns + * @param array $value + * @return $this + */ + public function whereNotIn(string $columns, array $value): static + { + if (empty($value) || !is_array($value)) { + $value = [-1]; + } + $this->where[] = ['NOT IN', $columns, $value]; + return $this; + } + + /** + * @param string $column + * @param int $start + * @param int $end + * @return $this + */ + public function whereBetween(string $column, int $start, int $end): static + { + if (empty($column) || empty($start) || empty($end)) { + return $this; + } + + $this->where[] = $column . ' BETWEEN ' . $start . ' AND ' . $end; + + return $this; + } + + /** + * @param string $column + * @param int $start + * @param int $end + * @return $this + */ + public function whereNotBetween(string $column, int $start, int $end): static + { + if (empty($column) || empty($start) || empty($end)) { + return $this; + } + + $this->where[] = $column . 'NOT BETWEEN' . $start . ' AND ' . $end; + + return $this; + } + + /** + * @param array $params + * + * @return $this + */ + public function bindParams(array $params = []): static + { + if (empty($params)) { + return $this; + } + $this->attributes = $params; + return $this; + } + + /** + * @param Closure|array|string $column + * @param string $opera + * @param null $value + * @return $this + * @throws NotFindClassException + * @throws ReflectionException + */ + public function where(Closure|array|string $column, string $opera = '=', $value = null): static + { + if (is_array($column)) { + return $this->addArray($column); + } + if ($column instanceof Closure) { + $this->where[] = $this->makeClosureFunction($column); + return $this; + } + if (is_string($column)) { + $this->where[] = $column; + } else { + [$column, $opera, $value] = $this->opera(...func_get_args()); + $this->where[] = "$column $opera $value"; + } + return $this; + } + + + /** + * @param Closure|array $closure + * @return string + * @throws NotFindClassException + * @throws ReflectionException + * @throws Exception + */ + public function makeClosureFunction(Closure|array $closure): string + { + $generate = $this->makeNewSqlGenerate(); + if ($closure instanceof Closure) { + call_user_func($closure, $generate); + } else { + $generate->where($closure); + } + return $generate->getSql(); + } + + + /** + * @param string $name + * @param string|null $having + * + * @return $this + */ + public function groupBy(string $name, string $having = NULL): static + { + $this->group = $name; + if (empty($having)) { + return $this; + } + $this->group .= ' HAVING ' . $having; + return $this; + } + + /** + * @param int $offset + * @param int $limit + * + * @return $this + */ + public function limit(int $offset, int $limit = 20): static + { + $this->offset = $offset; + $this->limit = $limit; + return $this; + } + + + /** + * @return array + */ + private function opera(): array + { + if (func_num_args() == 3) { + [$column, $opera, $value] = func_get_args(); + } else { + [$column, $value] = func_get_args(); + } + if (!isset($opera)) { + $opera = '='; + } + return [$column, $opera, $value]; + } + + + /** + * @param array $array + * @return $this + */ + private function addArray(array $array): static + { + foreach ($array as $key => $value) { + if (is_null($value)) continue; + if (is_numeric($key)) { + [$column, $opera, $value] = $this->opera(...$value); + + $this->where[] = $this->sprintf($column, $value, $opera); + } else { + $this->where[] = $this->sprintf($key, $value); + } + } + return $this; + } + + + /** + * @param $column + * @param $value + * @param string $opera + * @return string + */ + private function sprintf($column, $value, string $opera = '='): string + { + if (is_string($value)) { + $value = trim($value, '\'"'); + } + return "$column $opera '$value'"; + } + + + /** + * @return $this + */ + public function oneLimit(): static + { + $this->limit = 1; + return $this; + } + +} diff --git a/Traits/Relation.php b/Traits/Relation.php index 95915f5..5b40669 100644 --- a/Traits/Relation.php +++ b/Traits/Relation.php @@ -1,10 +1,10 @@ -_condition[] = 'CASE ' . $column; - } - - - /** - * @param string|int $condition - * @param string $then - * @return $this - * @throws Exception - */ - public function when(string|int $condition, string $then): static - { - $this->_condition[] = sprintf('WHEN %s THEN %s', $condition, $then); - - return $this; - } - - - /** - * @param string $alias - */ - public function else(string $alias) - { - $this->else = $alias; - } - - - /** - * @return string - */ - #[Pure] public function end(): string - { - if (empty($this->_condition)) { - return ''; - } - $prefix = implode(' ', $this->_condition); - if (!empty($this->else)) { - $prefix .= ' ELSE ' . $this->else; - } - return '(' . $prefix . ' END)'; - } - -} +_condition[] = 'CASE ' . $column; + } + + + /** + * @param string|int $condition + * @param string $then + * @return $this + * @throws Exception + */ + public function when(string|int $condition, string $then): static + { + $this->_condition[] = sprintf('WHEN %s THEN %s', $condition, $then); + + return $this; + } + + + /** + * @param string $alias + */ + public function else(string $alias) + { + $this->else = $alias; + } + + + /** + * @return string + */ + #[Pure] public function end(): string + { + if (empty($this->_condition)) { + return ''; + } + $prefix = implode(' ', $this->_condition); + if (!empty($this->else)) { + $prefix .= ' ELSE ' . $this->else; + } + return '(' . $prefix . ' END)'; + } + +}