Files

375 lines
10 KiB
PHP
Raw Permalink Normal View History

2022-01-09 03:49:51 +08:00
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/3/30 0030
* Time: 14:39
*/
declare(strict_types=1);
namespace Database;
2023-12-13 09:47:00 +08:00
use Database\Base\ActiveQueryInterface;
2022-01-09 03:49:51 +08:00
use Exception;
defined('SAVE_FAIL') or define('SAVE_FAIL', 3227);
defined('FIND_OR_CREATE_MESSAGE') or define('FIND_OR_CREATE_MESSAGE', 'Create a new model, but the data cannot be empty.');
/**
* Class Orm
* @package Database
*
* @property $attributes
* @property-read $oldAttributes
2023-12-13 09:47:00 +08:00
*
* @mixin ActiveQueryInterface
2022-01-09 03:49:51 +08:00
*/
class Model extends Base\Model
{
2023-07-10 11:28:53 +08:00
/**
* @param string $column
2023-08-29 15:19:39 +08:00
* @param int|float $value
2023-07-10 11:28:53 +08:00
* @return ModelInterface|false
2023-12-12 15:35:35 +08:00
* @throws
2023-07-10 11:28:53 +08:00
*/
2023-08-29 15:19:39 +08:00
public function increment(string $column, int|float $value): bool|ModelInterface
2023-07-10 11:28:53 +08:00
{
if (!$this->mathematics([$column => $value], '+')) {
return false;
}
$this->{$column} += $value;
return $this->refresh();
}
/**
* @param string $column
2023-08-29 15:19:39 +08:00
* @param int|float $value
2023-07-10 11:28:53 +08:00
* @return ModelInterface|false
2023-12-12 15:35:35 +08:00
* @throws
2023-07-10 11:28:53 +08:00
*/
2023-08-29 15:19:39 +08:00
public function decrement(string $column, int|float $value): bool|ModelInterface
2023-07-10 11:28:53 +08:00
{
if (!$this->mathematics([$column => $value], '-')) {
return false;
}
$this->{$column} -= $value;
return $this->refresh();
}
/**
* @param array $columns
* @return ModelInterface|false
2023-12-12 15:35:35 +08:00
* @throws
2023-07-10 11:28:53 +08:00
*/
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
2023-12-12 15:35:35 +08:00
* @throws
2023-07-10 11:28:53 +08:00
*/
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|static
2023-12-12 15:35:35 +08:00
* @throws
2023-07-10 11:28:53 +08:00
*/
public static function findOrCreate(array $condition, array $attributes): bool|static
{
2023-12-13 14:47:23 +08:00
$model = static::instance();
$connection = $model->getConnection()->beginTransaction();
try {
2023-07-10 11:28:53 +08:00
/** @var static $select */
2023-12-13 14:47:23 +08:00
$select = $model::query()->where($condition)->first();
2023-07-10 11:28:53 +08:00
if ($select === null) {
2023-12-13 14:47:23 +08:00
$select = $model::populate(array_merge($condition, $attributes));
if (!$select->save()) {
throw new Exception('保存失败: ' . $model->getLastError());
}
2023-07-10 11:28:53 +08:00
}
2023-12-13 14:47:23 +08:00
$connection->commit();
2023-07-10 11:28:53 +08:00
return $select;
2023-12-13 14:47:23 +08:00
} catch (\Throwable $throwable) {
2025-12-31 00:19:29 +08:00
$model->getLogger()->json_log($throwable);
$connection->rollback();
return false;
2023-12-13 14:47:23 +08:00
}
2023-07-10 11:28:53 +08:00
}
/**
* @param array $condition
* @param array $attributes
* @return bool|static
2023-12-12 15:35:35 +08:00
* @throws
2023-07-10 11:28:53 +08:00
*/
public static function createOrUpdate(array $condition, array $attributes = []): bool|static
{
2023-12-13 14:47:23 +08:00
$model = static::instance();
$connection = $model->getConnection()->beginTransaction();
try {
2023-07-10 11:28:53 +08:00
/** @var static $select */
$select = static::query()->where($condition)->first();
if (empty($select)) {
$select = static::populate($condition);
}
2023-10-24 17:22:29 +08:00
$select->attributes = $attributes;
2023-12-13 14:47:23 +08:00
if (!$select->save()) {
throw new Exception('保存失败: ' . $model->getLastError());
}
$connection->commit();
return $select;
} catch (\Throwable $throwable) {
2025-12-31 00:19:29 +08:00
$model->getLogger()->json_log($throwable);
$connection->rollback();
return false;
2023-12-13 14:47:23 +08:00
}
2023-07-10 11:28:53 +08:00
}
2023-12-13 09:47:00 +08:00
/**
* @param string $name
* @param array $arguments
2023-12-13 10:05:42 +08:00
* @return Model|ActiveQuery
2023-12-13 09:47:00 +08:00
*/
2023-12-13 10:05:42 +08:00
public static function __callStatic(string $name, array $arguments): static|ActiveQuery
2023-12-13 09:47:00 +08:00
{
// TODO: Change the autogenerated stub
if (method_exists(static::class, $name)) {
return call_user_func(static::class . '::' . $name, ...$arguments);
} else {
return static::query()->{$name}(...$arguments);
}
}
2023-07-10 11:28:53 +08:00
/**
2023-12-18 17:59:42 +08:00
* @param array $columns
* @param string $action
2023-07-10 11:28:53 +08:00
* @return array|bool|int|string|null
*/
2023-12-18 17:59:42 +08:00
private function mathematics(array $columns, string $action): int|bool|array|string|null
2023-07-10 11:28:53 +08:00
{
2023-12-13 14:47:23 +08:00
$condition = [$this->getPrimary() => $this->getPrimaryValue()];
2023-07-10 11:28:53 +08:00
$activeQuery = static::query()->where($condition);
2023-12-12 15:35:35 +08:00
$create = SqlBuilder::builder($activeQuery)->mathematics($columns, $action);
2023-07-10 11:28:53 +08:00
if (is_bool($create)) {
return false;
}
2023-12-13 14:47:23 +08:00
return $activeQuery->buildCommand($create)->exec();
2023-07-10 11:28:53 +08:00
}
/**
* @param array $params
* @return ModelInterface|bool
2023-12-12 15:35:35 +08:00
* @throws
2023-07-10 11:28:53 +08:00
*/
public function update(array $params): static|bool
{
2024-01-10 17:35:55 +08:00
if (!$this->validator($this->rules(), $params) || !$this->beforeSave($this)) {
2023-07-10 11:28:53 +08:00
return FALSE;
}
2023-12-14 09:50:49 +08:00
return $this->updateInternal(...$this->arrayIntersect($params));
2023-07-10 11:28:53 +08:00
}
/**
* @param array $data
* @return bool
2023-12-12 15:35:35 +08:00
* @throws
2023-07-10 11:28:53 +08:00
*/
public static function inserts(array $data): bool
{
if (empty($data)) {
2025-12-31 00:19:29 +08:00
return \Kiri::getLogger()->logCategory('Insert data empty.', 'mysql');
} else {
return static::query()->insert($data);
}
2023-07-10 11:28:53 +08:00
}
/**
* @return bool
2023-12-12 15:35:35 +08:00
* @throws
2023-07-10 11:28:53 +08:00
*/
public function delete(): bool
{
2023-12-13 14:47:23 +08:00
if (!$this->beforeDelete()) {
return false;
2023-07-10 11:28:53 +08:00
}
2023-12-13 14:47:23 +08:00
if ($this->hasPrimary()) {
$result = static::deleteByCondition(['id' => $this->getPrimaryValue()]);
} else {
$result = static::deleteByCondition($this->_attributes);
2023-07-10 11:28:53 +08:00
}
2023-12-13 14:47:23 +08:00
return $this->afterDelete($result);
2023-07-10 11:28:53 +08:00
}
/**
* @return array
2023-12-12 15:35:35 +08:00
* @throws
2023-07-10 11:28:53 +08:00
*/
public function toArray(): array
{
$data = $this->_attributes;
foreach ($data as $key => $datum) {
$method = 'get' . ucfirst($key) . 'Attribute';
if (!method_exists($this, $method)) {
continue;
}
$data[$key] = $this->{$method}($datum);
}
return $this->withs($data);
}
/**
2023-12-18 17:59:42 +08:00
* @param array $data
2023-07-10 11:28:53 +08:00
* @return array
*/
2023-12-18 17:59:42 +08:00
private function withs(array $data): array
2023-07-10 11:28:53 +08:00
{
$with = $this->getWith();
foreach ($with as $value) {
$join = $this->withRelate($value);
2023-11-13 17:52:38 +08:00
if ($join instanceof \Arrayable) {
2023-07-10 11:28:53 +08:00
$join = $join->toArray();
}
$data[$value] = $join;
}
return $data;
}
/**
2024-11-06 20:52:17 +08:00
* @param string $modelName
2023-12-18 17:59:42 +08:00
* @param string $foreignKey
* @param string $localKey
2023-07-10 11:28:53 +08:00
* @return string
2023-12-18 17:59:42 +08:00
* @throws Exception
2023-07-10 11:28:53 +08:00
*/
2024-11-06 20:52:17 +08:00
private function _hasBase(string $modelName, string $foreignKey, string $localKey): string
2023-07-10 11:28:53 +08:00
{
if (($value = $this->{$localKey}) === null) {
throw new Exception("Need join table primary key.");
}
2024-11-06 21:06:01 +08:00
$relation = di(Relation::class);
2023-07-10 11:28:53 +08:00
2024-11-06 21:13:12 +08:00
$primaryKey = str_replace('\\', '_', $modelName) . '_' . $foreignKey . '_' . $value;
2023-07-10 11:28:53 +08:00
if (!$relation->hasIdentification($primaryKey)) {
2026-06-12 23:57:19 +08:00
/** @var $modelName ModelInterface */
2023-07-10 11:28:53 +08:00
$relation->bindIdentification($primaryKey, $modelName::query()->where([$foreignKey => $value]));
}
return $primaryKey;
}
/**
2024-11-06 20:52:17 +08:00
* @param string $modelName
2023-12-18 17:59:42 +08:00
* @param string $foreignKey
* @param string $localKey
2023-07-10 11:28:53 +08:00
* @return HasOne|ActiveQuery
2023-12-18 17:59:42 +08:00
* @throws Exception
2023-07-10 11:28:53 +08:00
*/
2024-11-06 20:52:17 +08:00
public function hasOne(string $modelName, string $foreignKey, string $localKey): HasOne|ActiveQuery
2023-07-10 11:28:53 +08:00
{
return new HasOne($this->_hasBase($modelName, $foreignKey, $localKey));
}
/**
2024-11-06 20:52:17 +08:00
* @param string $modelName
2023-12-18 17:59:42 +08:00
* @param string $foreignKey
* @param string $localKey
2023-07-10 11:28:53 +08:00
* @return ActiveQuery|HasCount
2023-12-18 17:59:42 +08:00
* @throws Exception
2023-07-10 11:28:53 +08:00
*/
2024-11-06 20:52:17 +08:00
public function hasCount(string $modelName, string $foreignKey, string $localKey): ActiveQuery|HasCount
2023-07-10 11:28:53 +08:00
{
return new HasCount($this->_hasBase($modelName, $foreignKey, $localKey));
}
/**
2024-11-06 20:52:17 +08:00
* @param string $modelName
2023-12-18 17:59:42 +08:00
* @param string $foreignKey
* @param string $localKey
2023-07-10 11:28:53 +08:00
* @return ActiveQuery|HasMany
2023-12-18 17:59:42 +08:00
* @throws Exception
2023-07-10 11:28:53 +08:00
*/
2024-11-06 20:52:17 +08:00
public function hasMany(string $modelName, string $foreignKey, string $localKey): ActiveQuery|HasMany
2023-07-10 11:28:53 +08:00
{
return new HasMany($this->_hasBase($modelName, $foreignKey, $localKey));
}
/**
2024-11-06 20:52:17 +08:00
* @param string $modelName
2023-12-18 17:59:42 +08:00
* @param string $foreignKey
* @param string $localKey
2023-07-10 11:28:53 +08:00
* @return ActiveQuery|HasMany
2023-12-18 17:59:42 +08:00
* @throws Exception
2023-07-10 11:28:53 +08:00
*/
2024-11-06 20:52:17 +08:00
public function hasIn(string $modelName, string $foreignKey, string $localKey): ActiveQuery|HasMany
2023-07-10 11:28:53 +08:00
{
if (($value = $this->{$localKey}) === null) {
throw new Exception("Need join table primary key.");
}
2024-11-06 21:06:01 +08:00
$relation = di(Relation::class);
2023-07-10 11:28:53 +08:00
2024-11-06 21:13:12 +08:00
$primaryKey = str_replace('\\', '_', $modelName) . '_' . $foreignKey . '_' . implode('_', $value);
2023-07-10 11:28:53 +08:00
if (!$relation->hasIdentification($primaryKey)) {
2026-06-12 23:57:19 +08:00
/** @var $modelName ModelInterface */
2023-07-10 11:28:53 +08:00
$relation->bindIdentification($primaryKey, $modelName::query()->whereIn($foreignKey, $value));
}
return new HasMany($primaryKey);
}
/**
* @param bool $result
* @return bool
*/
public function afterDelete(bool $result): bool
{
return $result;
}
/**
* @return bool
* @throws Exception
*/
public function beforeDelete(): bool
{
return TRUE;
}
2022-01-09 03:49:51 +08:00
}