From 079cd12399a2d0297e17f0120886a6c3fd9581e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mr=C2=B7x?= Date: Tue, 28 Sep 2021 18:54:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ActiveQuery.php | 18 +- src/ActiveRecord.php | 445 -------------- src/Annotation/Relation.php | 3 - src/Base/AbstractCollection.php | 34 +- src/Base/CollectionIterator.php | 12 +- src/Collection.php | 12 +- src/Connection.php | 31 +- src/HasCount.php | 4 +- src/HasMany.php | 4 +- src/HasOne.php | 4 +- src/IOrm.php | 50 -- src/{Base/BaseActiveRecord.php => Model.php} | 574 ++++++++++++++++--- src/ModelInterface.php | 60 ++ src/SqlBuilder.php | 4 +- src/TestModel.php | 26 + src/Traits/Builder.php | 4 +- src/Traits/HasBase.php | 21 +- src/Traits/QueryTrait.php | 31 +- 18 files changed, 659 insertions(+), 678 deletions(-) delete mode 100644 src/ActiveRecord.php delete mode 100644 src/IOrm.php rename src/{Base/BaseActiveRecord.php => Model.php} (59%) create mode 100644 src/ModelInterface.php create mode 100644 src/TestModel.php diff --git a/src/ActiveQuery.php b/src/ActiveQuery.php index e52c308..5a51be8 100644 --- a/src/ActiveQuery.php +++ b/src/ActiveQuery.php @@ -118,15 +118,15 @@ class ActiveQuery extends Component implements ISqlBuilder */ public function execute($sql, array $params = []): Command { - return $this->modelClass::getDb()->createCommand($sql, $params); + return $this->modelClass->getConnection()->createCommand($sql, $params); } /** - * @return ActiveRecord|null + * @return ModelInterface|null * @throws Exception */ - public function first(): ActiveRecord|null + public function first(): ModelInterface|null { $data = $this->execute($this->builder->one())->one(); if (empty($data)) { @@ -207,22 +207,22 @@ class ActiveQuery extends Component implements ISqlBuilder } /** - * @param ActiveRecord $model + * @param ModelInterface $model * @param $data - * @return ActiveRecord + * @return ModelInterface * @throws Exception */ - public function populate(ActiveRecord $model, $data): ActiveRecord + public function populate(ModelInterface $model, $data): ModelInterface { return $this->getWith($model::populate($data)); } /** - * @param ActiveRecord $model - * @return ActiveRecord + * @param ModelInterface $model + * @return ModelInterface */ - public function getWith(ActiveRecord $model): ActiveRecord + public function getWith(ModelInterface $model): ModelInterface { if (empty($this->with) || !is_array($this->with)) { return $model; diff --git a/src/ActiveRecord.php b/src/ActiveRecord.php deleted file mode 100644 index 882f2ea..0000000 --- a/src/ActiveRecord.php +++ /dev/null @@ -1,445 +0,0 @@ -mathematics([$column => $value], '+', null)) { - return false; - } - $this->{$column} += $value; - return $this->refresh(); - } - - - /** - * @param string $column - * @param int $value - * @return ActiveRecord|false - * @throws Exception - */ - public function decrement(string $column, int $value): bool|ActiveRecord - { - if (!$this->mathematics([$column => $value], '-', null)) { - return false; - } - $this->{$column} -= $value; - return $this->refresh(); - } - - - /** - * @param array $columns - * @return ActiveRecord|false - * @throws Exception - */ - public function increments(array $columns): bool|static - { - if (!$this->mathematics($columns, '+', null)) { - return false; - } - foreach ($columns as $key => $attribute) { - $this->$key += $attribute; - } - return $this; - } - - - /** - * @param array $columns - * @return ActiveRecord|false - * @throws Exception - */ - public function decrements(array $columns): bool|static - { - if (!$this->mathematics($columns, '-', null)) { - return false; - } - foreach ($columns as $key => $attribute) { - $this->$key -= $attribute; - } - return $this; - } - - /** - * @param array $condition - * @param array $attributes - * @return bool|ActiveRecord - * @throws ReflectionException - * @throws NotFindClassException - * @throws Exception - */ - public static function findOrCreate(array $condition, array $attributes = []): bool|static - { - $logger = Kiri::app()->getLogger(); - - /** @var static $select */ - $select = static::find()->where($condition)->first(); - if (!empty($select)) { - return $select; - } - if (empty($attributes)) { - return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql'); - } - $select = duplicate(static::class); - $select->attributes = $attributes; - if (!$select->save()) { - return $logger->addError($select->getLastError(), 'mysql'); - } - 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'); - } - /** @var static $select */ - $select = static::find()->where($condition)->first(); - if (empty($select)) { - $select = duplicate(static::class); - } - $select->attributes = $attributes; - if (!$select->save()) { - return $logger->addError($select->getLastError(), 'mysql'); - } - 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): int|bool|array|string|null - { - if (empty($condition)) { - $condition = [$this->getPrimary() => $this->getPrimaryValue()]; - } - - $activeQuery = static::find()->where($condition); - $create = SqlBuilder::builder($activeQuery)->mathematics($columns, $action); - if (is_bool($create)) { - return false; - } - return static::getDb()->createCommand($create[0], $create[1])->exec(); - } - - - /** - * @param array $fields - * @return ActiveRecord|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 - { - /** @var static $class */ - $class = Kiri::createObject(['class' => static::class]); - if (empty($data)) { - return $class->addError('Insert data empty.', 'mysql'); - } - return $class::find()->batchInsert($data); - } - - /** - * @return bool - * @throws Exception - */ - public function delete(): bool - { - $conditions = $this->_oldAttributes; - if (empty($conditions)) { - return $this->addError("Delete condition do not empty.", 'mysql'); - } - $primary = $this->getPrimary(); - - if (!empty($primary)) { - $conditions = [$primary => $this->getAttribute($primary)]; - } - return static::deleteByCondition($conditions); - } - - - /** - * @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::find()->where($condition); - return $condition->batchUpdate($attributes); - } - - - /** - * @param $condition - * @return ActiveRecord|null - * @throws NotFindClassException - * @throws ReflectionException - * @throws Exception - */ - public static function first($condition): ?ActiveRecord - { - return static::query()->where($condition)->first(); - } - - - /** - * @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::find()->where($condition); - if (!empty($attributes)) { - $query->bindParams($attributes); - } - return $query->all(); - } - - /** - * @param $method - * @return mixed - * @throws Exception - */ - private function resolveObject($method): mixed - { - $resolve = $this->{$this->getRelate($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 array_merge($data, $this->runRelate()); - } - - /** - * @return array - * @throws Exception - */ - private function runRelate(): array - { - $relates = []; - if (empty($with = $this->getWith())) { - return $relates; - } - foreach ($with as $val) { - $relates[$val] = $this->resolveObject($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->getAttribute($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->getAttribute($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->getAttribute($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->getAttribute($localKey)) === null) { - throw new Exception("Need join table primary key."); - } - - $relation = $this->getRelation(); - - return new HasMany($modelName, $foreignKey, $value, $relation); - } - - /** - * @return bool - * @throws Exception - */ - public function afterDelete(): bool - { - if (!$this->hasPrimary()) { - return TRUE; - } - $value = $this->getPrimaryValue(); - if (empty($value)) { - return TRUE; - } - return TRUE; - } - - /** - * @return bool - * @throws Exception - */ - public function beforeDelete(): bool - { - if (!$this->hasPrimary()) { - return TRUE; - } - $value = $this->getPrimaryValue(); - if (empty($value)) { - return TRUE; - } - return TRUE; - } -} diff --git a/src/Annotation/Relation.php b/src/Annotation/Relation.php index b542cfa..73a11f7 100644 --- a/src/Annotation/Relation.php +++ b/src/Annotation/Relation.php @@ -5,11 +5,8 @@ namespace Database\Annotation; use Annotation\Attribute; -use Database\ActiveRecord; use Database\Base\Relate; use Exception; -use JetBrains\PhpStorm\Pure; -use Kiri\Kiri; /** diff --git a/src/Base/AbstractCollection.php b/src/Base/AbstractCollection.php index a48b640..003b19c 100644 --- a/src/Base/AbstractCollection.php +++ b/src/Base/AbstractCollection.php @@ -12,7 +12,7 @@ namespace Database\Base; use ArrayIterator; use Database\ActiveQuery; -use Database\ActiveRecord; +use Database\ModelInterface; use Kiri\ToArray; use Exception; use JetBrains\PhpStorm\Pure; @@ -27,11 +27,11 @@ abstract class AbstractCollection extends Component implements \IteratorAggregat { /** - * @var ActiveRecord[] + * @var ModelInterface[] */ protected array $_item = []; - protected ActiveRecord|string|null $model; + protected ModelInterface|string|null $model; protected ActiveQuery $query; @@ -42,19 +42,19 @@ abstract class AbstractCollection extends Component implements \IteratorAggregat } - /** - * Collection constructor. - * - * @param $query - * @param array $array - * @param string|ActiveRecord|null $model - * @throws Exception - */ - public function __construct($query, array $array = [], string|ActiveRecord $model = null) + /** + * 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 = duplicate($model); + $this->model = $model; parent::__construct([]); } @@ -108,7 +108,7 @@ abstract class AbstractCollection extends Component implements \IteratorAggregat * @return mixed * @throws Exception */ - public function getModel(): ActiveRecord + public function getModel(): ModelInterface { return $this->model; } @@ -125,15 +125,15 @@ abstract class AbstractCollection extends Component implements \IteratorAggregat /** * @param mixed $offset - * @return ActiveRecord|null + * @return ModelInterface|null * @throws Exception */ - public function offsetGet(mixed $offset): ?ActiveRecord + public function offsetGet(mixed $offset): ?ModelInterface { if (!$this->offsetExists($offset)) { return NULL; } - if (!($this->_item[$offset] instanceof ActiveRecord)) { + if (!($this->_item[$offset] instanceof ModelInterface)) { return $this->model->setAttributes($this->_item[$offset]); } return $this->_item[$offset]; diff --git a/src/Base/CollectionIterator.php b/src/Base/CollectionIterator.php index 3025502..6614fc7 100644 --- a/src/Base/CollectionIterator.php +++ b/src/Base/CollectionIterator.php @@ -6,7 +6,7 @@ namespace Database\Base; use Database\ActiveQuery; -use Database\ActiveRecord; +use Database\ModelInterface; use Exception; @@ -17,14 +17,14 @@ use Exception; class CollectionIterator extends \ArrayIterator { - private ActiveRecord|string $model; + private ModelInterface|string $model; /** @var ActiveQuery */ private ActiveQuery $query; - private ?ActiveRecord $_clone = null; + private ?ModelInterface $_clone = null; public function clean() @@ -51,10 +51,10 @@ class CollectionIterator extends \ArrayIterator /** * @param $current - * @return ActiveRecord + * @return ModelInterface * @throws Exception */ - protected function newModel($current): ActiveRecord + protected function newModel($current): ModelInterface { return $this->model->setAttributes($current); } @@ -63,7 +63,7 @@ class CollectionIterator extends \ArrayIterator /** * @throws Exception */ - public function current(): ActiveRecord + public function current(): ModelInterface { if (is_array($current = parent::current())) { $current = $this->newModel($current); diff --git a/src/Collection.php b/src/Collection.php index acfe4de..4ad0f7d 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -44,7 +44,7 @@ class Collection extends AbstractCollection $_tmp = []; $data = $this->toArray(); foreach ($data as $val) { - /** @var ActiveRecord $val */ + /** @var ModelInterface $val */ $_tmp[] = $val[$field]; } return $_tmp; @@ -93,7 +93,7 @@ class Collection extends AbstractCollection } /** - * @param $field + * @param string $field * @param string $setKey * * @return array|null @@ -126,9 +126,9 @@ class Collection extends AbstractCollection } /** - * @return ActiveRecord|array + * @return ModelInterface|array */ - #[Pure] public function current(): ActiveRecord|array + #[Pure] public function current(): ModelInterface|array { return current($this->_item); } @@ -173,7 +173,7 @@ class Collection extends AbstractCollection $ids[] = $id; } } - return $model::find()->whereIn($model->getPrimary(), $ids)->delete(); + return $model::query()->whereIn($model->getPrimary(), $ids)->delete(); } /** @@ -206,7 +206,7 @@ class Collection extends AbstractCollection private function filterCheck($value, $condition): bool { $_value = $value; - if ($_value instanceof ActiveRecord) { + if ($_value instanceof ModelInterface) { $_value = $_value->toArray(); } $_tmp = array_intersect_key($_value, $condition); diff --git a/src/Connection.php b/src/Connection.php index 018c54b..1db9c8a 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -12,21 +12,20 @@ namespace Database; use Annotation\Inject; +use Database\Affair\BeginTransaction; +use Database\Affair\Commit; +use Database\Affair\Rollback; +use Database\Mysql\PDO; use Database\Mysql\Schema; use Exception; -use JetBrains\PhpStorm\Pure; -use Database\Mysql\PDO; -use ReflectionException; -use Server\Events\OnWorkerExit; -use Server\Events\OnWorkerStop; use Kiri\Abstracts\Component; use Kiri\Abstracts\Config; use Kiri\Events\EventProvider; use Kiri\Exception\NotFindClassException; use Kiri\Kiri; -use Database\Affair\BeginTransaction; -use Database\Affair\Commit; -use Database\Affair\Rollback; +use ReflectionException; +use Server\Events\OnWorkerExit; +use Server\Events\OnWorkerStop; /** * Class Connection @@ -91,8 +90,8 @@ class Connection extends Component $this->eventProvider->on(Commit::class, [$this, 'commit'], 0); if (Db::transactionsActive()) { - $this->beginTransaction(); - } + $this->beginTransaction(); + } $this->_schema->db = $this; } @@ -138,12 +137,12 @@ class Connection extends Component } } - /** - * @return mixed - * @throws ReflectionException - * @throws NotFindClassException - * @throws \Exception - */ + /** + * @return mixed + * @throws ReflectionException + * @throws NotFindClassException + * @throws \Exception + */ public function getSchema(): Schema { if ($this->_schema === null) { diff --git a/src/HasCount.php b/src/HasCount.php index a993fa6..67d0dbf 100644 --- a/src/HasCount.php +++ b/src/HasCount.php @@ -28,10 +28,10 @@ class HasCount extends HasBase } /** - * @return array|null|ActiveRecord + * @return array|null|ModelInterface * @throws Exception */ - public function get(): array|ActiveRecord|null + public function get(): array|ModelInterface|null { return $this->_relation->count($this->model::className(), $this->value); } diff --git a/src/HasMany.php b/src/HasMany.php index 24f08d8..933e9f4 100644 --- a/src/HasMany.php +++ b/src/HasMany.php @@ -34,10 +34,10 @@ class HasMany extends HasBase } /** - * @return array|null|ActiveRecord + * @return array|null|ModelInterface * @throws Exception */ - public function get(): array|ActiveRecord|null + public function get(): array|ModelInterface|null { return $this->_relation->get($this->model::className(), $this->value); } diff --git a/src/HasOne.php b/src/HasOne.php index 347eec6..24cc991 100644 --- a/src/HasOne.php +++ b/src/HasOne.php @@ -35,10 +35,10 @@ class HasOne extends HasBase } /** - * @return array|null|ActiveRecord + * @return array|null|ModelInterface * @throws Exception */ - public function get(): array|ActiveRecord|null + public function get(): array|ModelInterface|null { return $this->_relation->first($this->model::className(), $this->value); } diff --git a/src/IOrm.php b/src/IOrm.php deleted file mode 100644 index 4e3d9a5..0000000 --- a/src/IOrm.php +++ /dev/null @@ -1,50 +0,0 @@ -getSetter(static::class, $name); if (!empty($method)) { $value = $this->{$method}($value); } - return $this->_attributes[$name] = $value; + $this->_attributes[$name] = $value; } @@ -184,7 +174,6 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, /** * @return EventDispatch - * @throws ReflectionException */ protected function getEventDispatch(): EventDispatch { @@ -194,7 +183,7 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, /** * @param $data - * @return ActiveRecord + * @return ModelInterface */ public function setWith($data): static { @@ -292,7 +281,7 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, if ($this->primary !== NULL) { return true; } - $primary = static::getColumns()->getPrimaryKeys(); + $primary = $this->getColumns()->getPrimaryKeys(); if (!empty($primary)) { return $this->primary = is_array($primary) ? current($primary) : $primary; } @@ -313,7 +302,7 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, */ public function getAutoIncrement(): int|string|null { - return static::getColumns()->getAutoIncrement(); + return $this->getColumns()->getAutoIncrement(); } /** @@ -343,7 +332,7 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, /** * @param $param * @param null $db - * @return BaseActiveRecord|null + * @return Model|null * @throws NotFindClassException * @throws ReflectionException * @throws Exception @@ -356,7 +345,7 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, if (is_numeric($param)) { $param = static::getPrimaryCondition($param); } - return static::find()->where($param)->first(); + return static::query()->where($param)->first(); } @@ -367,7 +356,7 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, */ private static function getPrimaryCondition($param): array { - $primary = static::getColumns()->getPrimaryKeys(); + $primary = static::makeNewInstance()->getColumns()->getPrimaryKeys(); if (empty($primary)) { throw new Exception('Primary key cannot be empty.'); } @@ -380,13 +369,13 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, /** * @param null $field - * @return ActiveRecord|null + * @return ModelInterface|null * @throws Exception * @throws Exception */ - public static function max($field = null): ?ActiveRecord + public static function max($field = null): ?ModelInterface { - $columns = static::getColumns(); + $columns = static::makeNewInstance()->getColumns(); if (empty($field)) { $field = $columns->getFirstPrimary(); } @@ -394,7 +383,7 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, if (!isset($columns[$field])) { return null; } - $first = static::find()->max($field)->first(); + $first = static::query()->max($field)->first(); if (empty($first)) { return null; } @@ -403,11 +392,41 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, /** - * @return ActiveQuery + * @param string|int $param + * @return Model|null + * @throws NotFindClassException + * @throws ReflectionException + * @throws Exception */ - public static function find(): ActiveQuery + public static function find(string|int $param): ?static { - return static::query(); + $columns = duplicate(static::class)->getPrimary(); + if (empty($columns)) { + $columns = static::makeNewInstance()->getColumns()->getFirstPrimary(); + } + return static::query()->where([$columns => $param])->first(); + } + + + /** + * @return static + */ + 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(); } @@ -416,16 +435,16 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, */ public static function query(): ActiveQuery { - return new ActiveQuery(get_called_class()); + return new ActiveQuery(new static()); } /** - * @throws ConfigException + * @return Connection */ - protected function getConnection() + public function getConnection(): Connection { - return Config::get('databases.connections.' . $this->connection, null, true); + return Kiri::app()->get('db')->get($this->connection); } @@ -443,9 +462,9 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, if (!$if_condition_is_null) { return false; } - return static::find()->delete(); + return static::query()->delete(); } - $model = static::find()->ifNotWhere($if_condition_is_null)->where($condition); + $model = static::query()->ifNotWhere($if_condition_is_null)->where($condition); if (!empty($attributes)) { $model->bindParams($attributes); } @@ -527,8 +546,8 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, */ private function insert($param, $attributes): bool|static { - [$sql, $param] = SqlBuilder::builder(static::find())->insert($param); - $dbConnection = static::getDb()->createCommand($sql, $param); + [$sql, $param] = SqlBuilder::builder(static::query())->insert($param); + $dbConnection = $this->getConnection()->createCommand($sql, $param); if (!($lastId = (int)$dbConnection->save(true, $this))) { throw new Exception('保存失败.'); } @@ -580,11 +599,11 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, if ($this->hasPrimary()) { $condition = [$this->getPrimary() => $this->getPrimaryValue()]; } - $generate = SqlBuilder::builder(static::find()->where($condition))->update($param); + $generate = SqlBuilder::builder(static::query()->where($condition))->update($param); if (is_bool($generate)) { return $generate; } - $command = static::getDb()->createCommand($generate[0], $generate[1]); + $command = $this->getConnection()->createCommand($generate[0], $generate[1]); if ($command->save(false, $this)) { return $this->refresh()->afterSave($fields, $param); } @@ -779,26 +798,26 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, */ public function has($attribute): bool { - return static::getColumns()->hasField($attribute); + return static::makeNewInstance()->getColumns()->hasField($attribute); } /**ƒ * @return string * @throws Exception */ - public static function getTable(): string + public function getTable(): string { - $tablePrefix = static::getDb()->tablePrefix; + $connection = static::getConnection(); - $table = static::tableName(); - if (empty($table)) { + $tablePrefix = $connection->tablePrefix; + if (empty($this->table)) { throw new Exception('You need add static method `tableName` and return table name.'); } - $table = trim($table, '{{%}}'); - if (!empty($tablePrefix) && !str_starts_with($table, $tablePrefix)) { - $table = $tablePrefix . $table; + $table = trim($this->table, '{{%}}'); + if (!empty($tablePrefix) && !str_starts_with($this->table, $tablePrefix)) { + $table = $tablePrefix . $this->table; } - return '`' . static::getDatabase() . '`.' . $table; + return '`' . $connection->database . '`.' . $table; } @@ -824,18 +843,404 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, } - private static string $ab_name = ''; + /** + * @return array + */ + public function rules(): array + { + return []; + } + + /** + * @param string $column + * @param int $value + * @return ModelInterface|false + * @throws Exception + */ + public function increment(string $column, int $value): bool|ModelInterface + { + if (!$this->mathematics([$column => $value], '+')) { + return false; + } + $this->{$column} += $value; + return $this->refresh(); + } /** - * @return Connection + * @param string $column + * @param int $value + * @return ModelInterface|false * @throws Exception */ - public static function getDb(): Connection + public function decrement(string $column, int $value): bool|ModelInterface { - return static::setDatabaseConnect('db'); + 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(); + + /** @var static $select */ + $select = static::query()->where($condition)->first(); + if (!empty($select)) { + return $select; + } + if (empty($attributes)) { + return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql'); + } + $select = duplicate(static::class); + $select->attributes = $attributes; + if (!$select->save()) { + return $logger->addError($select->getLastError(), 'mysql'); + } + 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'); + } + /** @var static $select */ + $select = static::query()->where($condition)->first(); + if (empty($select)) { + $select = duplicate(static::class); + } + $select->attributes = $attributes; + if (!$select->save()) { + return $logger->addError($select->getLastError(), 'mysql'); + } + 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 + { + $conditions = $this->_oldAttributes; + if (empty($conditions)) { + return $this->addError("Delete condition do not empty.", 'mysql'); + } + $primary = $this->getPrimary(); + + if (!empty($primary)) { + $conditions = [$primary => $this->getAttribute($primary)]; + } + return static::deleteByCondition($conditions); + } + + + /** + * @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 resolveObject($method): mixed + { + $resolve = $this->{$this->getRelate($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 array_merge($data, $this->runRelate()); + } + + /** + * @return array + * @throws Exception + */ + private function runRelate(): array + { + $relates = []; + if (empty($with = $this->getWith())) { + return $relates; + } + foreach ($with as $val) { + $relates[$val] = $this->resolveObject($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->getAttribute($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->getAttribute($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->getAttribute($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->getAttribute($localKey)) === null) { + throw new Exception("Need join table primary key."); + } + + $relation = $this->getRelation(); + + return new HasMany($modelName, $foreignKey, $value, $relation); + } + + /** + * @return bool + * @throws Exception + */ + public function afterDelete(): bool + { + if (!$this->hasPrimary()) { + return TRUE; + } + $value = $this->getPrimaryValue(); + if (empty($value)) { + return TRUE; + } + return TRUE; + } + + /** + * @return bool + * @throws Exception + */ + public function beforeDelete(): bool + { + if (!$this->hasPrimary()) { + return TRUE; + } + $value = $this->getPrimaryValue(); + if (empty($value)) { + return TRUE; + } + return TRUE; + } + + /** * @return static */ @@ -885,7 +1290,7 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, */ private function _decode($name, $value): mixed { - return static::getColumns()->_decode($name, $value); + return $this->getColumns()->_decode($name, $value); } @@ -1027,36 +1432,14 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, } - /** - * @param $dbName - * @return mixed - * @throws Exception - */ - public static function setDatabaseConnect($dbName): Connection - { - return Kiri::app()->get('db')->get(static::$_connection = $dbName); - } - - - /** - * @return string - * @throws ConfigException - */ - public static function getDatabase(): string - { - return Config::get('databases.connections.' . static::$_connection . '.database'); - } - - /** * @return Columns * @throws Exception */ - public static function getColumns(): Columns + public function getColumns(): Columns { - return static::getDb()->getSchema() - ->getColumns() - ->table(static::getTable()); + return $this->getConnection()->getSchema()->getColumns() + ->table($this->getTable()); } /** @@ -1086,4 +1469,15 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess, }; } + + /** + * @param string $name + * @param array $arguments + * @return mixed + */ + public static function __callStatic(string $name, array $arguments) + { + return (new static())->{$name}(...$arguments); + } + } diff --git a/src/ModelInterface.php b/src/ModelInterface.php new file mode 100644 index 0000000..385a423 --- /dev/null +++ b/src/ModelInterface.php @@ -0,0 +1,60 @@ +query->modelClass::getTable()); + $delete = sprintf('DELETE FROM %s ', $this->query->modelClass->getTable()); $this->query->from = null; @@ -361,7 +361,7 @@ class SqlBuilder extends Component $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->modelClass->getTable(); } return $this->query->from; } diff --git a/src/TestModel.php b/src/TestModel.php new file mode 100644 index 0000000..6dc417b --- /dev/null +++ b/src/TestModel.php @@ -0,0 +1,26 @@ +get(); diff --git a/src/Traits/Builder.php b/src/Traits/Builder.php index ea7d12e..6193555 100644 --- a/src/Traits/Builder.php +++ b/src/Traits/Builder.php @@ -167,9 +167,7 @@ trait Builder * @param $condition * @param $array * @return string - * @throws NotFindClassException - * @throws ReflectionException - * @throws ReflectionException + * @throws Exception */ private function _arrayMap($condition, $array): string { diff --git a/src/Traits/HasBase.php b/src/Traits/HasBase.php index 51d6413..0b874e8 100644 --- a/src/Traits/HasBase.php +++ b/src/Traits/HasBase.php @@ -9,9 +9,8 @@ declare(strict_types=1); namespace Database\Traits; -use Database\ActiveRecord; +use Database\ModelInterface; use Database\Collection; -use Database\IOrm; use Database\Relation; use Exception; @@ -24,11 +23,11 @@ use Exception; abstract class HasBase implements \Database\Traits\Relation { - /** @var ActiveRecord|Collection */ - protected Collection|ActiveRecord $data; + /** @var ModelInterface|Collection */ + protected Collection|ModelInterface $data; /** - * @var IOrm|ActiveRecord + * @var ModelInterface */ protected mixed $model; @@ -40,7 +39,7 @@ abstract class HasBase implements \Database\Traits\Relation /** * HasBase constructor. - * @param IOrm $model + * @param ModelInterface $model * @param $primaryId * @param $value * @param Relation $relation @@ -49,16 +48,16 @@ abstract class HasBase implements \Database\Traits\Relation public function __construct(mixed $model, $primaryId, $value, Relation $relation) { if (!class_exists($model)) { - throw new Exception('Model must implement ' . ActiveRecord::class); + throw new Exception('Model must implement ' . $model); } - if (!in_array(IOrm::class, class_implements($model))) { - throw new Exception('Model must implement ' . ActiveRecord::class); + if (!in_array(ModelInterface::class, class_implements($model))) { + throw new Exception('Model must implement ' . $model); } if (is_array($value)) { if (empty($value)) $value = []; - $_model = $model::find()->whereIn($primaryId, $value); + $_model = $model::query()->whereIn($primaryId, $value); } else { - $_model = $model::find()->where(['t1.' . $primaryId => $value]); + $_model = $model::query()->where(['t1.' . $primaryId => $value]); } $this->_relation = $relation->bindIdentification($model, $_model); diff --git a/src/Traits/QueryTrait.php b/src/Traits/QueryTrait.php index d2d8737..be33a54 100644 --- a/src/Traits/QueryTrait.php +++ b/src/Traits/QueryTrait.php @@ -12,8 +12,8 @@ namespace Database\Traits; use Closure; use Database\ActiveQuery; -use Database\ActiveRecord; use Database\Condition\MathematicsCondition; +use Database\ModelInterface; use Database\Query; use Database\SqlBuilder; use Exception; @@ -44,9 +44,9 @@ trait QueryTrait private SqlBuilder $builder; /** - * @var ActiveRecord|string|null + * @var ModelInterface|string|null */ - public ActiveRecord|string|null $modelClass; + public ModelInterface|string|null $modelClass; /** * clear @@ -140,7 +140,7 @@ trait QueryTrait */ public function getTable(): string { - return $this->modelClass::getTable(); + return $this->modelClass->getTable(); } @@ -306,10 +306,11 @@ trait QueryTrait public function leftJoin(string $tableName, string $alias, $onCondition, $param = NULL): static { if (class_exists($tableName)) { - if (!in_array(ActiveRecord::class, class_implements($tableName))) { - throw new Exception('Model must implement ' . $tableName); + $model = Kiri::getDi()->get($tableName); + if (!($model instanceof ModelInterface)) { + throw new Exception('Model must implement ' . ModelInterface::class); } - $tableName = $tableName::getTable(); + $tableName = $model->getTable(); } return $this->join(...["LEFT JOIN " . $tableName, $alias, $onCondition, $param]); } @@ -325,10 +326,11 @@ trait QueryTrait public function rightJoin($tableName, $alias, $onCondition, $param = NULL): static { if (class_exists($tableName)) { - if (!in_array(ActiveRecord::class, class_implements($tableName))) { - throw new Exception('Model must implement ' . $tableName); + $model = Kiri::getDi()->get($tableName); + if (!($model instanceof ModelInterface)) { + throw new Exception('Model must implement ' . ModelInterface::class); } - $tableName = $tableName::getTable(); + $tableName = $model->getTable(); } return $this->join(...["RIGHT JOIN " . $tableName, $alias, $onCondition, $param]); } @@ -344,10 +346,11 @@ trait QueryTrait public function innerJoin($tableName, $alias, $onCondition, $param = NULL): static { if (class_exists($tableName)) { - if (!in_array(ActiveRecord::class, class_implements($tableName))) { - throw new Exception('Model must implement ' . $tableName); + $model = Kiri::getDi()->get($tableName); + if (!($model instanceof ModelInterface)) { + throw new Exception('Model must implement ' . ModelInterface::class); } - $tableName = $tableName::getTable(); + $tableName = $model->getTable(); } return $this->join(...["INNER JOIN " . $tableName, $alias, $onCondition, $param]); } @@ -727,7 +730,7 @@ trait QueryTrait $activeQuery = new ActiveQuery($this->modelClass); call_user_func($value, $activeQuery); if (empty($activeQuery->from)) { - $activeQuery->from($activeQuery->modelClass::getTable()); + $activeQuery->from($activeQuery->modelClass->getTable()); } return $activeQuery; }