Files
kiri-core/Database/ActiveRecord.php
T

447 lines
9.2 KiB
PHP
Raw Normal View History

2020-08-31 12:38:32 +08:00
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/3/30 0030
* Time: 14:39
*/
2020-10-29 18:17:25 +08:00
declare(strict_types=1);
2020-11-10 11:36:39 +08:00
2020-08-31 12:38:32 +08:00
namespace Database;
use Database\Base\BaseActiveRecord;
2021-04-16 21:33:20 +08:00
use Database\Traits\HasBase;
use Exception;
2021-02-25 16:43:40 +08:00
use ReflectionException;
2021-03-29 17:47:13 +08:00
use Snowflake\Channel;
2021-02-25 16:43:40 +08:00
use Snowflake\Exception\NotFindClassException;
2020-09-10 16:22:31 +08:00
use Snowflake\Snowflake;
2020-08-31 12:38:32 +08:00
defined('SAVE_FAIL') or define('SAVE_FAIL', 3227);
2020-09-25 15:37:33 +08:00
defined('FIND_OR_CREATE_MESSAGE') or define('FIND_OR_CREATE_MESSAGE', 'Create a new model, but the data cannot be empty.');
2020-08-31 12:38:32 +08:00
/**
* Class Orm
* @package Database
*
* @property $attributes
* @property-read $oldAttributes
* @method beforeSearch($model)
*/
class ActiveRecord extends BaseActiveRecord
{
2020-11-17 18:48:26 +08:00
const DECR = 'decr';
const INCR = 'incr';
/**
* @return array
*/
2020-12-17 14:09:14 +08:00
public function rules(): array
2020-11-17 18:48:26 +08:00
{
return [];
}
/**
* @param string $column
* @param int $value
* @return ActiveRecord|false
* @throws Exception
*/
2020-12-17 14:09:14 +08:00
public function increment(string $column, int $value): bool|ActiveRecord
2020-11-17 18:48:26 +08:00
{
2021-03-04 23:53:41 +08:00
if (!$this->mathematics([$column => $value], '+')) {
2020-11-17 18:48:26 +08:00
return false;
}
$this->{$column} += $value;
return $this->refresh();
}
/**
* @param string $column
* @param int $value
* @return ActiveRecord|false
* @throws Exception
*/
2020-12-17 14:09:14 +08:00
public function decrement(string $column, int $value): bool|ActiveRecord
2020-11-17 18:48:26 +08:00
{
2021-02-25 17:57:20 +08:00
if (!$this->mathematics([$column => $value], '-')) {
2020-11-17 18:48:26 +08:00
return false;
}
$this->{$column} -= $value;
return $this->refresh();
}
/**
* @param array $columns
* @return ActiveRecord|false
* @throws Exception
*/
2020-12-17 14:09:14 +08:00
public function increments(array $columns): bool|static
2020-11-17 18:48:26 +08:00
{
2021-02-25 17:57:20 +08:00
if (!$this->mathematics($columns, '+')) {
2020-11-17 18:48:26 +08:00
return false;
}
foreach ($columns as $key => $attribute) {
$this->$key += $attribute;
}
return $this;
}
/**
* @param array $columns
* @return ActiveRecord|false
* @throws Exception
*/
2020-12-17 14:09:14 +08:00
public function decrements(array $columns): bool|static
2020-11-17 18:48:26 +08:00
{
2021-02-25 17:57:20 +08:00
if (!$this->mathematics($columns, '-')) {
2020-11-17 18:48:26 +08:00
return false;
}
foreach ($columns as $key => $attribute) {
$this->$key -= $attribute;
}
return $this;
}
/**
2020-12-17 14:09:14 +08:00
* @param array $condition
* @param array $attributes
2021-02-25 16:43:40 +08:00
* @return bool|ActiveRecord
* @throws ReflectionException
* @throws NotFindClassException
2020-11-17 18:48:26 +08:00
* @throws Exception
*/
2021-02-25 16:43:40 +08:00
public static function findOrCreate(array $condition, array $attributes = []): bool|static
2020-11-17 18:48:26 +08:00
{
2021-03-31 01:58:36 +08:00
$logger = Snowflake::app()->getLogger();
2021-02-25 16:43:40 +08:00
/** @var static $select */
2020-11-18 15:05:33 +08:00
$select = static::find()->where($condition)->first();
2020-11-17 18:48:26 +08:00
if (!empty($select)) {
return $select;
}
if (empty($attributes)) {
2021-03-31 01:58:36 +08:00
return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql');
2020-11-17 18:48:26 +08:00
}
2021-03-31 01:54:05 +08:00
$select = self::getModelClass();
$select->attributes = $attributes;
if (!$select->save()) {
2021-03-31 01:58:36 +08:00
return $logger->addError($select->getLastError(), 'mysql');
2021-03-31 01:54:05 +08:00
}
return $select;
}
2021-02-24 14:22:56 +08:00
2021-03-31 01:54:05 +08:00
/**
* @param array $condition
* @param array $attributes
* @return bool|static
* @throws Exception
*/
2021-03-31 01:56:56 +08:00
public static function createOrUpdate(array $condition, array $attributes = []): bool|static
2021-03-31 01:54:05 +08:00
{
2021-03-31 01:58:36 +08:00
$logger = Snowflake::app()->getLogger();
2021-03-31 01:54:05 +08:00
if (empty($attributes)) {
2021-03-31 01:58:36 +08:00
return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql');
2021-03-31 01:54:05 +08:00
}
/** @var static $select */
$select = static::find()->where($condition)->first();
if (empty($select)) {
$select = self::getModelClass();
}
2020-11-17 18:48:26 +08:00
$select->attributes = $attributes;
2020-11-17 18:48:55 +08:00
if (!$select->save()) {
2021-03-31 01:58:36 +08:00
return $logger->addError($select->getLastError(), 'mysql');
2020-11-17 18:48:26 +08:00
}
return $select;
}
2021-03-31 01:54:05 +08:00
/**
* @return static
* @throws Exception
*/
private static function getModelClass(): static
{
$className = get_called_class();
/** @var Channel $channel */
$channel = Snowflake::app()->get('channel');
return $channel->pop($className, function () use ($className) {
return new $className();
});
}
2020-11-17 18:48:26 +08:00
/**
* @param $action
* @param $columns
* @param array $condition
* @return array|bool|int|string|null
* @throws Exception
*/
2021-02-25 17:57:20 +08:00
private function mathematics($columns, $action, $condition = []): int|bool|array|string|null
2020-11-17 18:48:26 +08:00
{
if (empty($condition)) {
$condition = [$this->getPrimary() => $this->getPrimaryValue()];
}
2021-02-25 17:57:20 +08:00
$activeQuery = static::find()->where($condition);
2021-02-25 18:03:17 +08:00
$create = SqlBuilder::builder($activeQuery)->mathematics($columns, $action);
if (is_bool($create)) {
return false;
}
2021-02-25 18:06:41 +08:00
return static::getDb()->createCommand($create[0], $create[1])->exec();
2020-11-17 18:48:26 +08:00
}
/**
2021-02-25 17:25:30 +08:00
* @param array $fields
2020-12-17 15:20:43 +08:00
* @return ActiveRecord|bool
* @throws Exception
2020-11-17 18:48:26 +08:00
*/
2021-02-25 17:25:30 +08:00
public function update(array $fields): static|bool
2020-11-17 18:48:26 +08:00
{
2021-02-25 17:25:30 +08:00
return $this->save($fields);
2020-11-17 18:48:26 +08:00
}
/**
* @param array $data
* @return bool
* @throws Exception
*/
2021-02-25 18:26:15 +08:00
public static function inserts(array $data): bool
2020-11-17 18:48:26 +08:00
{
/** @var static $class */
2021-04-16 21:33:20 +08:00
$class = Snowflake::createObject(['class' => static::class]);
2020-11-17 18:48:26 +08:00
if (empty($data)) {
return $class->addError('Insert data empty.', 'mysql');
}
return $class::find()->batchInsert($data);
}
/**
* @return bool
* @throws Exception
*/
2020-12-17 14:09:14 +08:00
public function delete(): bool
2020-11-17 18:48:26 +08:00
{
$conditions = $this->_oldAttributes;
if (empty($conditions)) {
return $this->addError("Delete condition do not empty.", 'mysql');
}
$primary = $this->getPrimary();
if (!empty($primary)) {
2021-02-25 18:28:02 +08:00
$conditions = [$primary => $this->getAttribute($primary)];
2020-11-17 18:48:26 +08:00
}
2021-02-25 18:28:02 +08:00
return static::deleteByCondition($conditions);
2020-11-17 18:48:26 +08:00
}
/**
* @param $condition
* @param array $attributes
*
* @return bool
* @throws Exception
*/
2021-02-25 18:26:15 +08:00
public static function updateAll(mixed $condition, $attributes = []): bool
2020-11-17 18:48:26 +08:00
{
$condition = static::find()->where($condition);
return $condition->batchUpdate($attributes);
}
/**
* @param $condition
* @param array $attributes
*
2020-12-17 14:09:14 +08:00
* @return array|Collection
2020-11-17 18:48:26 +08:00
* @throws Exception
*/
2020-12-17 14:09:14 +08:00
public static function findAll($condition, $attributes = []): array|Collection
2020-11-17 18:48:26 +08:00
{
$query = static::find()->where($condition);
if (!empty($attributes)) {
$query->bindParams($attributes);
}
return $query->all();
}
/**
2021-03-04 14:34:21 +08:00
* @param $method
2020-12-17 14:09:14 +08:00
* @return mixed
2020-11-17 18:48:26 +08:00
* @throws Exception
*/
2021-03-04 14:34:21 +08:00
private function resolveObject($method): mixed
2020-11-17 18:48:26 +08:00
{
2021-03-04 15:05:46 +08:00
$resolve = $this->{$this->getRelate($method)}();
2021-01-26 17:08:56 +08:00
if ($resolve instanceof HasBase) {
$resolve = $resolve->get();
}
2020-11-26 10:49:59 +08:00
if ($resolve instanceof Collection) {
return $resolve->toArray();
2021-03-04 14:34:21 +08:00
} else if ($resolve instanceof ActiveRecord) {
2020-11-26 10:49:59 +08:00
return $resolve->toArray();
2021-03-04 14:34:21 +08:00
} else if (is_object($resolve)) {
2020-11-26 10:49:59 +08:00
return get_object_vars($resolve);
2021-03-04 14:34:21 +08:00
} else {
return $resolve;
2020-11-26 10:49:59 +08:00
}
2020-11-17 18:48:26 +08:00
}
/**
2020-12-17 14:09:14 +08:00
* @return array
2020-11-17 18:48:26 +08:00
* @throws Exception
*/
2020-12-17 14:09:14 +08:00
public function toArray(): array
2020-11-17 18:48:26 +08:00
{
2021-01-19 19:13:27 +08:00
$data = $this->_attributes;
2021-03-04 15:17:25 +08:00
foreach ($this->getAnnotation(self::ANNOTATION_GET) as $key => $item) {
2021-03-05 18:18:14 +08:00
if (!isset($data[$key])) continue;
2021-03-05 18:08:47 +08:00
$data[$key] = $this->runAnnotation($key, $data[$key] ?? null);
2021-01-19 19:22:57 +08:00
}
2021-02-23 17:43:13 +08:00
$data = array_merge($data, $this->runRelate());
return $data;
}
2020-11-17 18:48:26 +08:00
/**
* @return array
* @throws Exception
*/
2020-12-17 14:09:14 +08:00
private function runRelate(): array
2020-11-17 18:48:26 +08:00
{
$relates = [];
2021-03-04 15:34:49 +08:00
if (empty($with = $this->getWith())) {
2020-11-17 18:48:26 +08:00
return $relates;
}
2021-03-04 15:34:49 +08:00
foreach ($with as $val) {
2021-03-04 15:05:46 +08:00
$relates[$val] = $this->resolveObject($val);
2020-11-17 18:48:26 +08:00
}
return $relates;
}
/**
2020-12-17 14:09:14 +08:00
* @param string $modelName
2020-11-17 18:48:26 +08:00
* @param $foreignKey
* @param $localKey
2021-01-16 17:02:08 +08:00
* @return ActiveQuery
2020-11-17 18:48:26 +08:00
* @throws Exception
*/
2021-01-16 17:02:08 +08:00
public function hasOne(string $modelName, $foreignKey, $localKey): mixed
2020-11-17 18:48:26 +08:00
{
if (!$this->has($localKey)) {
throw new Exception("Need join table primary key.");
}
$value = $this->getAttribute($localKey);
$relation = $this->getRelation();
2021-02-24 14:22:56 +08:00
return new HasOne($modelName, $foreignKey, $value, $relation);
2020-11-17 18:48:26 +08:00
}
/**
* @param $modelName
* @param $foreignKey
* @param $localKey
2021-01-16 17:02:08 +08:00
* @return ActiveQuery
2020-11-17 18:48:26 +08:00
* @throws Exception
*/
2021-01-16 17:02:08 +08:00
public function hasCount($modelName, $foreignKey, $localKey): mixed
2020-11-17 18:48:26 +08:00
{
if (!$this->has($localKey)) {
throw new Exception("Need join table primary key.");
}
$value = $this->getAttribute($localKey);
$relation = $this->getRelation();
2021-02-24 14:22:56 +08:00
return new HasCount($modelName, $foreignKey, $value, $relation);
2020-11-17 18:48:26 +08:00
}
/**
* @param $modelName
* @param $foreignKey
* @param $localKey
2021-01-16 17:02:08 +08:00
* @return ActiveQuery
2020-11-17 18:48:26 +08:00
* @throws Exception
*/
2021-01-16 17:02:08 +08:00
public function hasMany($modelName, $foreignKey, $localKey): mixed
2020-11-17 18:48:26 +08:00
{
if (!$this->has($localKey)) {
throw new Exception("Need join table primary key.");
}
$value = $this->getAttribute($localKey);
$relation = $this->getRelation();
2021-02-24 14:22:56 +08:00
return new HasMany($modelName, $foreignKey, $value, $relation);
2020-11-17 18:48:26 +08:00
}
/**
* @param $modelName
* @param $foreignKey
* @param $localKey
2021-01-16 17:02:08 +08:00
* @return ActiveQuery
2020-11-17 18:48:26 +08:00
* @throws Exception
*/
2021-01-16 17:02:08 +08:00
public function hasIn($modelName, $foreignKey, $localKey): mixed
2020-11-17 18:48:26 +08:00
{
if (!$this->has($localKey)) {
throw new Exception("Need join table primary key.");
}
$value = $this->getAttribute($localKey);
$relation = $this->getRelation();
2021-02-24 14:22:56 +08:00
return new HasMany($modelName, $foreignKey, $value, $relation);
2020-11-17 18:48:26 +08:00
}
/**
* @return bool
* @throws Exception
*/
2020-12-17 14:09:14 +08:00
public function afterDelete(): bool
2020-11-17 18:48:26 +08:00
{
if (!$this->hasPrimary()) {
return TRUE;
}
$value = $this->getPrimaryValue();
if (empty($value)) {
return TRUE;
}
return TRUE;
}
/**
* @return bool
* @throws Exception
*/
2020-12-17 14:09:14 +08:00
public function beforeDelete(): bool
2020-11-17 18:48:26 +08:00
{
if (!$this->hasPrimary()) {
return TRUE;
}
$value = $this->getPrimaryValue();
if (empty($value)) {
return TRUE;
}
return TRUE;
}
2020-08-31 12:38:32 +08:00
}