2024-08-27 11:19:22 +08:00
|
|
|
<?php
|
|
|
|
|
/** @noinspection ALL */
|
2022-01-09 03:49:51 +08:00
|
|
|
/**
|
|
|
|
|
* Created by PhpStorm.
|
|
|
|
|
* User: whwyy
|
|
|
|
|
* Date: 2018/3/30 0030
|
|
|
|
|
* Time: 14:39
|
|
|
|
|
*/
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace Database\Base;
|
|
|
|
|
|
|
|
|
|
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.');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use ArrayAccess;
|
|
|
|
|
use Database\ActiveQuery;
|
2023-04-11 17:05:03 +08:00
|
|
|
use Database\Collection;
|
2022-01-09 03:49:51 +08:00
|
|
|
use Database\Connection;
|
2023-11-30 17:02:20 +08:00
|
|
|
use Database\DatabasesProviders;
|
2022-01-09 03:49:51 +08:00
|
|
|
use Database\ModelInterface;
|
|
|
|
|
use Database\Relation;
|
|
|
|
|
use Database\SqlBuilder;
|
|
|
|
|
use Exception;
|
2024-10-23 14:54:04 +08:00
|
|
|
use Kiri\Di\Context;
|
2022-02-23 16:32:08 +08:00
|
|
|
use Kiri;
|
2022-01-09 03:49:51 +08:00
|
|
|
use Kiri\Abstracts\Component;
|
2022-06-22 16:29:42 +08:00
|
|
|
use ReturnTypeWillChange;
|
2022-01-09 03:49:51 +08:00
|
|
|
use ReflectionException;
|
|
|
|
|
use validator\Validator;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Class BOrm
|
|
|
|
|
*
|
|
|
|
|
* @package Kiri\Abstracts
|
|
|
|
|
*
|
2024-12-29 21:10:58 +08:00
|
|
|
* @property bool $isNowExample
|
2022-01-09 03:49:51 +08:00
|
|
|
* @property array $attributes
|
|
|
|
|
* @property array $oldAttributes
|
|
|
|
|
*/
|
2023-11-13 17:52:38 +08:00
|
|
|
abstract class Model extends Component implements ModelInterface, ArrayAccess, \Arrayable
|
2022-01-09 03:49:51 +08:00
|
|
|
{
|
2023-04-05 10:15:50 +08:00
|
|
|
|
2024-12-29 21:10:58 +08:00
|
|
|
/** @var array */
|
|
|
|
|
protected array $_attributes = [];
|
2023-04-05 10:15:50 +08:00
|
|
|
|
2023-04-10 17:13:24 +08:00
|
|
|
|
2024-12-29 21:10:58 +08:00
|
|
|
/** @var array */
|
|
|
|
|
protected array $_oldAttributes = [];
|
2023-04-05 10:15:50 +08:00
|
|
|
|
|
|
|
|
|
2024-12-29 21:10:58 +08:00
|
|
|
/** @var null|string */
|
|
|
|
|
protected string $primary = '';
|
2023-04-05 10:15:50 +08:00
|
|
|
|
|
|
|
|
|
2024-12-29 21:10:58 +08:00
|
|
|
/**
|
|
|
|
|
* @var bool
|
|
|
|
|
*/
|
|
|
|
|
protected bool $isNewExample = TRUE;
|
2023-04-05 10:15:50 +08:00
|
|
|
|
|
|
|
|
|
2024-12-29 21:10:58 +08:00
|
|
|
/**
|
|
|
|
|
* @var bool
|
|
|
|
|
*/
|
|
|
|
|
protected bool $skipValidate = FALSE;
|
2023-04-05 10:15:50 +08:00
|
|
|
|
|
|
|
|
|
2024-12-29 21:10:58 +08:00
|
|
|
/**
|
|
|
|
|
* @var string
|
|
|
|
|
*/
|
|
|
|
|
protected string $table = '';
|
2023-04-05 10:15:50 +08:00
|
|
|
|
|
|
|
|
|
2024-12-29 21:10:58 +08:00
|
|
|
/**
|
|
|
|
|
* @var string
|
|
|
|
|
*/
|
|
|
|
|
protected string $connection = 'db';
|
2023-04-05 10:15:50 +08:00
|
|
|
|
|
|
|
|
|
2024-12-29 21:10:58 +08:00
|
|
|
/**
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
|
|
|
|
protected array $_with = [];
|
2023-04-05 10:15:50 +08:00
|
|
|
|
|
|
|
|
|
2024-12-29 21:10:58 +08:00
|
|
|
/**
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public function __construct()
|
|
|
|
|
{
|
|
|
|
|
parent::__construct();
|
2023-07-31 23:26:58 +08:00
|
|
|
|
2024-12-29 21:10:58 +08:00
|
|
|
$this->init();
|
|
|
|
|
}
|
2023-07-31 23:26:58 +08:00
|
|
|
|
|
|
|
|
|
2024-12-29 21:10:58 +08:00
|
|
|
/**
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function rules(): array
|
|
|
|
|
{
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array $data
|
|
|
|
|
*
|
|
|
|
|
* @return Model
|
|
|
|
|
*/
|
|
|
|
|
public function setWith(array $data): static
|
|
|
|
|
{
|
|
|
|
|
$this->_with = $data;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function getWith(): array
|
|
|
|
|
{
|
|
|
|
|
return $this->_with;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function hasWith(): bool
|
|
|
|
|
{
|
|
|
|
|
return count($this->_with) > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* object init
|
|
|
|
|
*/
|
|
|
|
|
public function clean(): void
|
|
|
|
|
{
|
|
|
|
|
$this->_attributes = [];
|
|
|
|
|
$this->_oldAttributes = [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public function init(): void
|
|
|
|
|
{
|
|
|
|
|
$container = Kiri::getDi();
|
|
|
|
|
$container->resolveProperties($container->getReflectionClass(get_called_class()), $this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @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
|
|
|
|
|
* get last exception or other error
|
|
|
|
|
*/
|
|
|
|
|
public function getLastError(): string
|
|
|
|
|
{
|
|
|
|
|
return $this->getLogger()->getLastError('mysql');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return bool
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function hasPrimary(): bool
|
|
|
|
|
{
|
|
|
|
|
return $this->primary != '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return null|string
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function getPrimary(): string
|
|
|
|
|
{
|
|
|
|
|
if (!$this->hasPrimary()) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
return $this->primary;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return bool
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function hasPrimaryValue(): bool
|
|
|
|
|
{
|
|
|
|
|
if ($this->hasPrimary()) {
|
|
|
|
|
return $this->getPrimaryValue() === NULL;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return int|null
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function getPrimaryValue(): ?int
|
|
|
|
|
{
|
|
|
|
|
if ($this->hasPrimary() && isset($this->_oldAttributes[$this->getPrimary()])) {
|
|
|
|
|
return (int)$this->_oldAttributes[$this->getPrimary()];
|
|
|
|
|
} else {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param int|string|array $param
|
|
|
|
|
*
|
|
|
|
|
* @return Model|null
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public static function findOne(int|string|array|null $param): ?static
|
|
|
|
|
{
|
|
|
|
|
if (empty($param)) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
$query = new ActiveQuery($model = static::instance());
|
|
|
|
|
$query->from($model->getTable())->alias('t1');
|
|
|
|
|
if (is_numeric($param)) {
|
|
|
|
|
$query->where([$model->getPrimary() => +$param]);
|
|
|
|
|
} else if (is_array($param)) {
|
|
|
|
|
$query->where($param);
|
|
|
|
|
} else {
|
|
|
|
|
$query->whereRaw($param);
|
|
|
|
|
}
|
|
|
|
|
if (($data = $query->first()) === FALSE) {
|
|
|
|
|
throw new Exception($model->getLastError());
|
|
|
|
|
} else {
|
|
|
|
|
return $data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param int $param
|
|
|
|
|
*
|
|
|
|
|
* @return Model|null
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public static function primary(int $param): ?static
|
|
|
|
|
{
|
|
|
|
|
$model = static::instance();
|
|
|
|
|
$query = new ActiveQuery($model);
|
|
|
|
|
$query->from($model->getTable())->alias('t1')->where([$model->getPrimary() => $param]);
|
|
|
|
|
return $query->first();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return bool|int
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public function optimize(): bool|int
|
|
|
|
|
{
|
|
|
|
|
return static::query()->execute('OPTIMIZE TABLE ' . $this->getTable());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return static
|
|
|
|
|
*/
|
|
|
|
|
protected static function instance(): static
|
|
|
|
|
{
|
|
|
|
|
return new static();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param int|string|array $condition
|
|
|
|
|
*
|
|
|
|
|
* @return static|null
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public static function first(int|string|array $condition): ?static
|
|
|
|
|
{
|
|
|
|
|
return static::findOne($condition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string|array $condition
|
|
|
|
|
*
|
|
|
|
|
* @return Collection
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public static function all(string|array $condition): Collection
|
|
|
|
|
{
|
|
|
|
|
$model = new ActiveQuery(static::instance());
|
|
|
|
|
$model->from($model->getTable())->alias('t1');
|
|
|
|
|
if (is_array($condition)) {
|
|
|
|
|
$model->where($condition);
|
|
|
|
|
} else {
|
|
|
|
|
$model->whereRaw($condition);
|
|
|
|
|
}
|
|
|
|
|
return $model->get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return ActiveQuery
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public static function query(): ActiveQuery
|
|
|
|
|
{
|
|
|
|
|
$model = new ActiveQuery(static::instance());
|
|
|
|
|
$model->select()->from($model->getTable())->alias('t1');
|
|
|
|
|
return $model;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return Connection
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function getConnection(): Connection
|
|
|
|
|
{
|
|
|
|
|
return Kiri::getDi()->get(DatabasesProviders::class)->get($this->connection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array|string $condition
|
|
|
|
|
* @param array $attributes
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
protected static function deleteByCondition(array|string $condition = [], array $attributes = []): bool
|
|
|
|
|
{
|
|
|
|
|
$model = static::query();
|
|
|
|
|
$model->bindParams($attributes);
|
|
|
|
|
if (is_string($condition)) {
|
|
|
|
|
$model->whereRaw($condition);
|
|
|
|
|
} else {
|
|
|
|
|
$model->where($condition);
|
|
|
|
|
}
|
|
|
|
|
return $model->delete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function getAttributes(): array
|
|
|
|
|
{
|
|
|
|
|
return $this->_attributes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function getOldAttributes(): array
|
|
|
|
|
{
|
|
|
|
|
return $this->_oldAttributes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $name
|
|
|
|
|
* @param mixed $value
|
|
|
|
|
*
|
|
|
|
|
* @return mixed
|
|
|
|
|
*/
|
|
|
|
|
public function setAttribute(string $name, mixed $value): mixed
|
|
|
|
|
{
|
|
|
|
|
$method = 'set' . ucfirst($name) . 'Attribute';
|
|
|
|
|
if (method_exists($this, $method)) {
|
|
|
|
|
$value = $this->{$method}($value);
|
|
|
|
|
}
|
|
|
|
|
return $this->_attributes[$name] = $value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $name
|
|
|
|
|
* @param mixed $value
|
|
|
|
|
*
|
|
|
|
|
* @return mixed
|
|
|
|
|
*/
|
|
|
|
|
public function setOldAttribute(string $name, mixed $value): mixed
|
|
|
|
|
{
|
|
|
|
|
$method = 'set' . ucfirst($name) . 'Attribute';
|
|
|
|
|
if (method_exists($this, $method)) {
|
|
|
|
|
$value = $this->{$method}($value);
|
|
|
|
|
}
|
|
|
|
|
return $this->_oldAttributes[$name] = $value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array $param
|
|
|
|
|
*
|
|
|
|
|
* @return $this
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function setAttributes(array $param): static
|
|
|
|
|
{
|
|
|
|
|
foreach ($param as $key => $attribute) {
|
|
|
|
|
$this->setAttribute($key, $attribute);
|
|
|
|
|
}
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array $param
|
|
|
|
|
*
|
|
|
|
|
* @return $this
|
|
|
|
|
*/
|
|
|
|
|
public function setOldAttributes(array $param): static
|
|
|
|
|
{
|
|
|
|
|
foreach ($param as $key => $attribute) {
|
|
|
|
|
$this->setOldAttribute($key, $attribute);
|
|
|
|
|
}
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return $this|bool
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
private function insert(): bool|static
|
|
|
|
|
{
|
|
|
|
|
$sql = SqlBuilder::builder($query = static::query())->insert($this->_attributes);
|
|
|
|
|
$lastId = $this->getConnection()->createCommand($sql, $query->params)->exec();
|
|
|
|
|
if ($lastId === FALSE) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!$this->hasPrimary()) {
|
|
|
|
|
return $this->refresh()->afterSave($this->_attributes, []);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->_attributes[$this->getPrimary()] = $lastId;
|
|
|
|
|
|
|
|
|
|
return $this->refresh()->afterSave($this->_attributes, [$this->getPrimary() => $lastId]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array $old
|
|
|
|
|
* @param array $condition
|
|
|
|
|
* @param array $change
|
|
|
|
|
*
|
|
|
|
|
* @return $this|bool
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
protected function updateInternal(array $old, array $condition, array $change): bool|static
|
|
|
|
|
{
|
|
|
|
|
$query = static::query()->where($condition);
|
|
|
|
|
if (count($change) < 1) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
$generate = SqlBuilder::builder($query)->update($change);
|
|
|
|
|
if ($generate === FALSE) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!$this->getConnection()->createCommand($generate, $query->params)->exec()) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return $this->refresh()->afterSave($old, $change);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return bool|$this
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function save(): static|bool
|
|
|
|
|
{
|
|
|
|
|
if (!$this->validator($this->rules(), $this->_attributes) || !$this->beforeSave($this)) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!$this->isNewExample) {
|
|
|
|
|
return $this->updateInternal(...$this->arrayIntersect($this->_attributes));
|
|
|
|
|
} else {
|
|
|
|
|
return $this->insert();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<array, array, array>
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
protected function arrayIntersect(array $params): array
|
|
|
|
|
{
|
|
|
|
|
$condition = [];
|
|
|
|
|
$oldPrams = [];
|
|
|
|
|
foreach ($this->_oldAttributes as $key => $attribute) {
|
|
|
|
|
if (!array_key_exists($key, $params) || $params[$key] == $attribute) {
|
|
|
|
|
$condition[$key] = $attribute;
|
|
|
|
|
unset($params[$key]);
|
|
|
|
|
} else {
|
|
|
|
|
$oldPrams[$key] = $this->_oldAttributes[$key];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ($this->hasPrimary()) {
|
|
|
|
|
$condition = [$this->getPrimary() => $this->getPrimaryValue()];
|
|
|
|
|
}
|
|
|
|
|
return [$oldPrams, $condition, $params];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function getChanges(): array
|
|
|
|
|
{
|
|
|
|
|
if (!$this->isNewExample) {
|
|
|
|
|
return \array_intersect_assoc($this->_oldAttributes, $this->_attributes);
|
|
|
|
|
}
|
|
|
|
|
return $this->_attributes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array $value
|
|
|
|
|
*
|
|
|
|
|
* @return $this
|
|
|
|
|
*/
|
|
|
|
|
public function populates(array $value): static
|
|
|
|
|
{
|
|
|
|
|
$this->_attributes = $value;
|
|
|
|
|
$this->_oldAttributes = $value;
|
|
|
|
|
$this->setIsNowExample();
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array $rule
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function validator(array $rule, array $params): bool
|
|
|
|
|
{
|
|
|
|
|
if (count($rule) < 1 || $this->skipValidate) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
$validate = $this->resolve($rule);
|
|
|
|
|
if (!$validate->validation($params)) {
|
|
|
|
|
return \Kiri::getLogger()->failure($validate->getError() . PHP_EOL, 'mysql');
|
|
|
|
|
} else {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array $rule
|
|
|
|
|
*
|
|
|
|
|
* @return Validator
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
private function resolve(array $rule): Validator
|
|
|
|
|
{
|
|
|
|
|
$validate = new Validator();
|
|
|
|
|
foreach ($rule as $val) {
|
|
|
|
|
$field = array_shift($val);
|
|
|
|
|
if (is_string($field)) {
|
|
|
|
|
$validate->make($this, [$field], $val);
|
|
|
|
|
} else {
|
|
|
|
|
$validate->make($this, $field, $val);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $validate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $name
|
|
|
|
|
*
|
|
|
|
|
* @return null
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function getAttribute(string $name): mixed
|
|
|
|
|
{
|
|
|
|
|
return $this->_attributes[$name] ?? NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return Relation|null
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function getRelation(): ?Relation
|
|
|
|
|
{
|
|
|
|
|
return di(Relation::class);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $attribute
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function has(string $attribute): bool
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**ƒ
|
|
|
|
|
* @return string
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function getTable(): string
|
|
|
|
|
{
|
|
|
|
|
$connection = $this->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 array $oldAttributes
|
|
|
|
|
* @param array $changeAttributes
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function afterSave(array $oldAttributes, array $changeAttributes): bool
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param self $model
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function beforeSave(self $model): bool
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return static
|
|
|
|
|
*/
|
|
|
|
|
public function refresh(): static
|
|
|
|
|
{
|
|
|
|
|
$this->_oldAttributes = $this->_attributes;
|
|
|
|
|
$this->isNewExample = FALSE;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $name
|
|
|
|
|
* @param mixed $value
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function __set(string $name, mixed $value): void
|
|
|
|
|
{
|
|
|
|
|
$prefix = 'set' . ucfirst($name);
|
|
|
|
|
if (method_exists($name, $prefix)) {
|
|
|
|
|
$this->{$prefix}($value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$method = $prefix . 'Attribute';
|
|
|
|
|
if (method_exists($this, $method)) {
|
|
|
|
|
$this->_attributes[$name] = $this->{$method} ($value);
|
|
|
|
|
} else {
|
|
|
|
|
$this->_attributes[$name] = $value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $name
|
|
|
|
|
*
|
|
|
|
|
* @return mixed
|
|
|
|
|
*/
|
|
|
|
|
public function __get(string $name): mixed
|
|
|
|
|
{
|
|
|
|
|
$value = $this->_attributes[$name] ?? NULL;
|
|
|
|
|
if (!method_exists($this, 'get' . ucfirst($name))) {
|
|
|
|
|
return $this->withPropertyOverride($name, $value);
|
|
|
|
|
} else {
|
|
|
|
|
return $this->withRelate($name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $name
|
|
|
|
|
* @param mixed|null $value
|
|
|
|
|
*
|
|
|
|
|
* @return mixed
|
|
|
|
|
*/
|
|
|
|
|
protected function withPropertyOverride(string $name, mixed $value = NULL): mixed
|
|
|
|
|
{
|
|
|
|
|
$method = 'get' . ucfirst($name) . 'Attribute';
|
|
|
|
|
if (method_exists($this, $method)) {
|
|
|
|
|
return $this->{$method}($value);
|
|
|
|
|
} else {
|
|
|
|
|
return $value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $name
|
|
|
|
|
* @param string $prefix
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
protected function hasRelateMethod(string $name): bool
|
|
|
|
|
{
|
|
|
|
|
$reflection = $this->container->get(static::class);
|
|
|
|
|
if (!$reflection->hasMethod($name)) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if ($reflection->getMethod($name)->isStatic() || !$reflection->getMethod($name)->isPublic()) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
} else {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $name
|
|
|
|
|
*
|
|
|
|
|
* @return mixed
|
|
|
|
|
*/
|
|
|
|
|
protected function withRelate(string $name): mixed
|
|
|
|
|
{
|
|
|
|
|
$response = $this->{'get' . ucfirst($name)}();
|
|
|
|
|
if ($response instanceof \Database\Traits\Relation) {
|
|
|
|
|
$response = $response->get();
|
|
|
|
|
}
|
|
|
|
|
return $response;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param $name
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function __isset(string $name): bool
|
|
|
|
|
{
|
|
|
|
|
return isset($this->_attributes[$name]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param mixed $offset
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function offsetExists(mixed $offset): bool
|
|
|
|
|
{
|
|
|
|
|
return isset($this->_attributes[$offset]) || isset($this->_oldAttributes[$offset]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param mixed $offset
|
|
|
|
|
*
|
|
|
|
|
* @return mixed
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public function offsetGet(mixed $offset): mixed
|
|
|
|
|
{
|
|
|
|
|
return $this->__get($offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param mixed $offset
|
|
|
|
|
* @param mixed $value
|
|
|
|
|
*
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
#[ReturnTypeWillChange]
|
|
|
|
|
public function offsetSet(mixed $offset, mixed $value): void
|
|
|
|
|
{
|
|
|
|
|
$this->__set($offset, $value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param mixed $offset
|
|
|
|
|
*
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
#[ReturnTypeWillChange]
|
|
|
|
|
public function offsetUnset(mixed $offset): void
|
|
|
|
|
{
|
|
|
|
|
if (!isset($this->_attributes[$offset]) && !isset($this->_oldAttributes[$offset])) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
unset($this->_attributes[$offset]);
|
|
|
|
|
unset($this->_oldAttributes[$offset]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string ...$params
|
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function unset(string ...$params): array
|
|
|
|
|
{
|
|
|
|
|
return array_diff_assoc($params, $this->_attributes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array $data
|
|
|
|
|
*
|
|
|
|
|
* @return static
|
|
|
|
|
* @throws
|
|
|
|
|
*/
|
|
|
|
|
public static function populate(array $data): static
|
|
|
|
|
{
|
|
|
|
|
$model = new static();
|
|
|
|
|
$model->_attributes = $data;
|
|
|
|
|
$model->_oldAttributes = $data;
|
|
|
|
|
$model->setIsNowExample();
|
|
|
|
|
return $model;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $name
|
|
|
|
|
* @param array $arguments
|
|
|
|
|
*
|
|
|
|
|
* @return mixed
|
|
|
|
|
*/
|
|
|
|
|
public static function __callStatic(string $name, array $arguments)
|
|
|
|
|
{
|
|
|
|
|
return (new static())->{$name}(...$arguments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $field
|
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function getOldAttribute(string $field): mixed
|
|
|
|
|
{
|
|
|
|
|
return $this->_oldAttributes[$field] ?? NULL;
|
|
|
|
|
}
|
2023-12-18 15:11:04 +08:00
|
|
|
|
2022-01-09 03:49:51 +08:00
|
|
|
}
|