优化代码
parent
08e04141e1
commit
c4b811db79
|
@ -3,21 +3,17 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Repository;
|
namespace App\Repository;
|
||||||
|
|
||||||
use App\Helper\ArrayHelper;
|
|
||||||
use App\Traits\PagingTrait;
|
|
||||||
use Hyperf\Database\Model\Model;
|
use Hyperf\Database\Model\Model;
|
||||||
use Hyperf\Database\Model\Builder;
|
use Hyperf\Database\Model\Builder;
|
||||||
use Hyperf\DbConnection\Db;
|
use Hyperf\DbConnection\Db;
|
||||||
use Hyperf\Utils\Arr;
|
|
||||||
use Hyperf\Utils\Collection;
|
use Hyperf\Utils\Collection;
|
||||||
use Exception;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BaseRepository
|
* Class BaseRepository 基础 Repository 类
|
||||||
*
|
*
|
||||||
* @method Model create(array $values) 新增数据
|
* @method Model create(array $values) 新增数据
|
||||||
* @method boolean insert(array $values) 新增数据
|
* @method boolean insert(array $values) 新增数据
|
||||||
* @method int|mixed insertGetId(array $values, $sequence = null) 新增数据获取新增ID
|
* @method int|mixed insertGetId(array $values) 新增数据并获取新增ID
|
||||||
* @method Model firstOrCreate(array $attributes, array $value = []) 查询数据没有就创建
|
* @method Model firstOrCreate(array $attributes, array $value = []) 查询数据没有就创建
|
||||||
* @method Model firstOrNew(array $attributes, array $value = []) 查询数据没有就实例化
|
* @method Model firstOrNew(array $attributes, array $value = []) 查询数据没有就实例化
|
||||||
* @method Model updateOrCreate(array $attributes, array $value = []) 查询修改没有就创建
|
* @method Model updateOrCreate(array $attributes, array $value = []) 查询修改没有就创建
|
||||||
|
@ -46,235 +42,7 @@ use Exception;
|
||||||
*/
|
*/
|
||||||
abstract class BaseRepository
|
abstract class BaseRepository
|
||||||
{
|
{
|
||||||
use PagingTrait;
|
use RepositoryTrait;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Model
|
|
||||||
*/
|
|
||||||
private $model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自带查询的表达式
|
|
||||||
*
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
private $operators = [
|
|
||||||
'=',
|
|
||||||
'<',
|
|
||||||
'>',
|
|
||||||
'<=',
|
|
||||||
'>=',
|
|
||||||
'<>',
|
|
||||||
'!=',
|
|
||||||
'<=>',
|
|
||||||
'like',
|
|
||||||
'like binary',
|
|
||||||
'not like',
|
|
||||||
'ilike',
|
|
||||||
'&',
|
|
||||||
'|',
|
|
||||||
'^',
|
|
||||||
'<<',
|
|
||||||
'>>',
|
|
||||||
'rlike',
|
|
||||||
'regexp',
|
|
||||||
'not regexp',
|
|
||||||
'~',
|
|
||||||
'~*',
|
|
||||||
'!~',
|
|
||||||
'!~*',
|
|
||||||
'similar to',
|
|
||||||
'not similar to',
|
|
||||||
'not ilike',
|
|
||||||
'~~*',
|
|
||||||
'!~~*'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 扩展查询的表达式
|
|
||||||
*
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
private $expression = [
|
|
||||||
'eq' => '=',
|
|
||||||
'neq' => '!=',
|
|
||||||
'ne' => '!=',
|
|
||||||
'gt' => '>',
|
|
||||||
'egt' => '>=',
|
|
||||||
'gte' => '>=',
|
|
||||||
'ge' => '>=',
|
|
||||||
'lt' => '<',
|
|
||||||
'le' => '<=',
|
|
||||||
'lte' => '<=',
|
|
||||||
'elt' => '<=',
|
|
||||||
'in' => 'In',
|
|
||||||
'not in' => 'NotIn',
|
|
||||||
'between' => 'Between',
|
|
||||||
'not between' => 'NotBetween',
|
|
||||||
'like' => 'like',
|
|
||||||
'not like' => 'not like',
|
|
||||||
'rlike' => 'rlike',
|
|
||||||
'<>' => '<>',
|
|
||||||
'<=>' => '<=>',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Model 不需要查询条件的方法
|
|
||||||
*
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
private $origin = [
|
|
||||||
'create', 'insert', 'insertGetId', 'getConnection', 'firstOrCreate', 'firstOrNew',
|
|
||||||
'updateOrCreate', 'findOrFail', 'findOrNew', 'updateOrInsert', 'find'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 父类需要查询条件的相关方法
|
|
||||||
*
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
private $parent = [
|
|
||||||
'count', 'max', 'min', 'avg', 'sum',
|
|
||||||
'increment', 'decrement',
|
|
||||||
'value', 'pluck',
|
|
||||||
'exists', 'doesntExist'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BaseRepository constructor.
|
|
||||||
* @param Model $model
|
|
||||||
*/
|
|
||||||
public function __construct(Model $model)
|
|
||||||
{
|
|
||||||
$this->model = $model;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用 model 的方法
|
|
||||||
*
|
|
||||||
* @param string $method 调用model 自己的方法
|
|
||||||
* @param array $arguments
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function __call(string $method, array $arguments)
|
|
||||||
{
|
|
||||||
// 直接使用 model, 不需要查询条件的数据
|
|
||||||
if (in_array($method, $this->origin)) {
|
|
||||||
return (new $this->model)->{$method}(...$arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调用 model 原生方法
|
|
||||||
if (in_array($method, $this->parent)) {
|
|
||||||
$where = Arr::pull($arguments, '0', []);
|
|
||||||
return $this->buildWhere($where)->{$method}(...$arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \Exception("Uncaught Error: Call to undefined method {$method}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取新的查询 Model
|
|
||||||
*
|
|
||||||
* @return Builder
|
|
||||||
*/
|
|
||||||
protected function getNewModel(): Builder
|
|
||||||
{
|
|
||||||
return $this->model->newQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理 where 条件
|
|
||||||
*
|
|
||||||
* @param array $where
|
|
||||||
* @return Builder
|
|
||||||
*/
|
|
||||||
final public function buildWhere(array $where = []): Builder
|
|
||||||
{
|
|
||||||
$model = $this->getNewModel();
|
|
||||||
|
|
||||||
// 处理排序数据
|
|
||||||
if ($order = Arr::pull($where, 'order by')) {
|
|
||||||
$this->addOrderBy($model, (array)$order);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理分组数据
|
|
||||||
if ($group = Arr::pull($where, 'group by')) {
|
|
||||||
$this->addGroupBy($model, (array)$group);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理分组数据
|
|
||||||
if ($having = Arr::pull($where, 'having by')) {
|
|
||||||
$this->addHaving($model, (array)$having);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断是否存在查询条件
|
|
||||||
if (!empty($where)) {
|
|
||||||
$this->bindWhere($model, $where);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $model;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Builder $model
|
|
||||||
* @param array $where
|
|
||||||
* @param bool $or
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
final private function bindWhere(Builder $model, array $where, $or = false)
|
|
||||||
{
|
|
||||||
foreach ($where as $field => $item) {
|
|
||||||
if ($field === 'or' || $field === 'and') {
|
|
||||||
$this->addNewWhere($model, $item, $or, $field);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_int($field)) {
|
|
||||||
if ($this->isModelQueryArray($item)) {
|
|
||||||
$model->{$or ? 'orWhere' : 'where'}(...$item);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->addNewWhere($model, $item, $or, $field);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 字段查询
|
|
||||||
$this->setFieldWhere($model, $field, $item, $or);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加 where 条件分组
|
|
||||||
*
|
|
||||||
* @param Builder $model
|
|
||||||
* @param array $where
|
|
||||||
* @param bool $or
|
|
||||||
* @param string $field
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
final private function addNewWhere(Builder $model, array $where, $or = false, $field = '')
|
|
||||||
{
|
|
||||||
$method = $or ? 'orWhere' : 'where';
|
|
||||||
|
|
||||||
$model->{$method}(function ($query) use ($where, $or, $field) {
|
|
||||||
$this->bindWhere($query, $where, $field === 'or');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据条件更新数据
|
|
||||||
*
|
|
||||||
* @param array $where
|
|
||||||
* @param array $values
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
final public function update(array $where, array $values): int
|
|
||||||
{
|
|
||||||
return $this->buildWhere($where)->update($values);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取单条数据
|
* 获取单条数据
|
||||||
|
@ -284,9 +52,9 @@ abstract class BaseRepository
|
||||||
* @param bool $is_array 是否返回数组格式
|
* @param bool $is_array 是否返回数组格式
|
||||||
* @return Builder|Model|object|array|null
|
* @return Builder|Model|object|array|null
|
||||||
*/
|
*/
|
||||||
public function first(array $where = [], array $fields = ['*'], bool $is_array = false)
|
final public function first(array $where = [], array $fields = ['*'], bool $is_array = false)
|
||||||
{
|
{
|
||||||
$this->handleFindField($fields);
|
$this->handleField($fields);
|
||||||
|
|
||||||
$data = $this->buildWhere($where)->first($fields);
|
$data = $this->buildWhere($where)->first($fields);
|
||||||
|
|
||||||
|
@ -305,9 +73,9 @@ abstract class BaseRepository
|
||||||
* @param bool $is_array 是否返回数组格式
|
* @param bool $is_array 是否返回数组格式
|
||||||
* @return Collection|array
|
* @return Collection|array
|
||||||
*/
|
*/
|
||||||
public function get(array $where = [], array $fields = ['*'], bool $is_array = false)
|
final public function get(array $where = [], array $fields = ['*'], bool $is_array = false)
|
||||||
{
|
{
|
||||||
$this->handleFindField($fields);
|
$this->handleField($fields);
|
||||||
|
|
||||||
$data = $this->buildWhere($where)->get($fields);
|
$data = $this->buildWhere($where)->get($fields);
|
||||||
|
|
||||||
|
@ -325,189 +93,110 @@ abstract class BaseRepository
|
||||||
* @param int $size 每页条数
|
* @param int $size 每页条数
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function paginate(array $where, $fields = ['*'], $page = 1, $size = 10): array
|
final public function paginate(array $where, $fields = ['*'], $page = 1, $size = 15): array
|
||||||
{
|
{
|
||||||
$this->handleFindField($fields);
|
$this->handleField($fields);
|
||||||
|
|
||||||
$result = $this->buildWhere($where)->paginate($size, $fields, 'page', $page);
|
$model = $this->buildWhere($where);
|
||||||
|
|
||||||
if (empty($result)) {
|
return $this->toPaginate($model, $fields, $page, $size);
|
||||||
return $this->getPagingRows([], 0, $page, $size);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过 model 读取分页信息
|
||||||
|
*
|
||||||
|
* @param Builder $model 查询 Model
|
||||||
|
* @param array $fields 查询字段
|
||||||
|
* @param int $page 当前分页
|
||||||
|
* @param int $size 分页大小
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toPaginate(Builder $model, array $fields = ['*'], int $page = 1, int $size = 15): array
|
||||||
|
{
|
||||||
|
$total = $model->count();
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'rows' => [],
|
||||||
|
'paginate' => [
|
||||||
|
'page' => $page,
|
||||||
|
'size' => $size,
|
||||||
|
'total' => $total,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($total > 0) {
|
||||||
|
$data['rows'] = $model->forPage($page, $size)->get($fields)->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getPagingRows(collect($result->items())->toArray(), $result->total(), $page, $size);
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件更新数据
|
||||||
|
*
|
||||||
|
* @param array $where 查询条件
|
||||||
|
* @param array $values 更新字段
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
final public function update(array $where, array $values): int
|
||||||
|
{
|
||||||
|
return $this->buildWhere($where)->update($values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新数据
|
||||||
|
*
|
||||||
|
* @param array $where 查询条件
|
||||||
|
* @param array $values 更新字段
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
final public function batchUpdate(array $where, array $values): int
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
foreach ($values as $field => $item) {
|
||||||
|
if (!is_array($item)) {
|
||||||
|
$data[$field] = $item;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$when = '';
|
||||||
|
foreach ($item['filter'] as $k => $v) {
|
||||||
|
$when .= sprintf(" when '%s' then '%s'", $k, $v);
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $item['field'] ?? $field;
|
||||||
|
|
||||||
|
$string = "case $key {$when} else '{$item['default']}' end";
|
||||||
|
|
||||||
|
$data[$field] = Db::raw($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($data)) return 0;
|
||||||
|
|
||||||
|
return $this->buildWhere($where)->update($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打印查询 sql
|
* 打印查询 sql
|
||||||
*
|
*
|
||||||
* @param array $where
|
* @param array $where 查询条件
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function toSql(array $where): string
|
final public function toSql(array $where): string
|
||||||
{
|
{
|
||||||
return $this->buildWhere($where)->toSql();
|
return $this->buildWhere($where)->toSql();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加排序信息
|
* 原生 sql 查询
|
||||||
*
|
*
|
||||||
* @param Builder $model
|
* @param string $query
|
||||||
* @param array $orders
|
* @param array $bindings
|
||||||
*/
|
* @param bool $useReadPdo
|
||||||
private function addOrderBy(Builder $model, array $orders)
|
|
||||||
{
|
|
||||||
foreach ($orders as $field => $sort) {
|
|
||||||
if ($this->isBackQuote($field)) {
|
|
||||||
$model->orderByRaw($this->trimBackQuote($field) . ' ' . $sort);
|
|
||||||
} else {
|
|
||||||
$model->orderBy($field, $sort);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加分组信息
|
|
||||||
*
|
|
||||||
* @param Builder $model
|
|
||||||
* @param array $groups
|
|
||||||
*/
|
|
||||||
private function addGroupBy(Builder $model, array $groups)
|
|
||||||
{
|
|
||||||
$model->groupBy(...$groups);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Builder $model
|
|
||||||
* @param array $items
|
|
||||||
*/
|
|
||||||
private function addHaving(Builder $model, array $items = [])
|
|
||||||
{
|
|
||||||
foreach ($items as $having) {
|
|
||||||
$model->{count($having) == 2 ? 'havingRaw' : 'having'}(...$having);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置条件查询
|
|
||||||
*
|
|
||||||
* @param Builder $model
|
|
||||||
* @param string $field
|
|
||||||
* @param string|int|array $value
|
|
||||||
* @param bool $or
|
|
||||||
* @return void
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
private function setFieldWhere(Builder $model, string $field, $value, $or = false): void
|
|
||||||
{
|
|
||||||
[$field, $operator] = $this->formatField($field);
|
|
||||||
|
|
||||||
// 查询数据是数组且未设置表达式,默认是 In 查询
|
|
||||||
if ($operator === 'eq' && is_array($value)) {
|
|
||||||
$operator = 'in';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证查询表达式
|
|
||||||
if (!isset($this->expression[$operator])) {
|
|
||||||
throw new \Exception("无效的 {$operator} 操作符!");
|
|
||||||
}
|
|
||||||
|
|
||||||
$method = $or ? 'orWhere' : 'where';
|
|
||||||
|
|
||||||
// 数组查询方式
|
|
||||||
if (in_array($this->expression[$operator], ['In', 'NotIn', 'Between', 'NotBetween'], true)) {
|
|
||||||
$method = $method . $this->expression[$operator];
|
|
||||||
$model->{$method}($field, (array)$value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$model->{$method}($field, $this->expression[$operator], $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析查询字段信息
|
|
||||||
*
|
|
||||||
* @param string $field 查询字段
|
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function formatField(string $field): array
|
final public function sql(string $query, array $bindings = [], bool $useReadPdo = true): array
|
||||||
{
|
{
|
||||||
$item = explode(':', $field);
|
return Db::select($query, $bindings, $useReadPdo);
|
||||||
$field = $item[0];
|
|
||||||
$operator = $item[1] ?? 'eq';
|
|
||||||
|
|
||||||
return [strtolower($field), trim($operator)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理查询字段
|
|
||||||
*
|
|
||||||
* @param array $fields 查询字段
|
|
||||||
*/
|
|
||||||
private function handleFindField(array &$fields)
|
|
||||||
{
|
|
||||||
foreach ($fields as $k => $field) {
|
|
||||||
$fields[$k] = $this->raw($field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 去除字段串两端反引号
|
|
||||||
*
|
|
||||||
* @param string $field
|
|
||||||
* @return \Hyperf\Database\Query\Expression|string
|
|
||||||
*/
|
|
||||||
private function raw(string $field)
|
|
||||||
{
|
|
||||||
// 匹配使用反引号的字段
|
|
||||||
if (!$this->isBackQuote($field)) return $field;
|
|
||||||
|
|
||||||
return Db::raw($this->trimBackQuote($field));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断字符串是否被反引号包含
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function isBackQuote(string $string): bool
|
|
||||||
{
|
|
||||||
return (bool)preg_match("/^`.*?`$/", $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 去除字符串两端的反引号
|
|
||||||
*
|
|
||||||
* @param string $field
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function trimBackQuote(string $field): string
|
|
||||||
{
|
|
||||||
return substr($field, 1, strlen($field) - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断是否是调用 where 最基本的方式是需要传递三个参数
|
|
||||||
*
|
|
||||||
* @param array $items
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function isModelQueryArray(array $items): bool
|
|
||||||
{
|
|
||||||
if (count($items) != 3) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断是否是关联数组
|
|
||||||
if (ArrayHelper::isRelationArray($items)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($items as $item) {
|
|
||||||
if (is_array($item)) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return in_array($items[1], $this->operators);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
namespace App\Repository;
|
namespace App\Repository;
|
||||||
|
|
||||||
use App\Helper\HashHelper;
|
use App\Helper\HashHelper;
|
||||||
|
use App\Model\Talk\TalkRecords;
|
||||||
use App\Model\User;
|
use App\Model\User;
|
||||||
use Hyperf\Utils\Str;
|
use Hyperf\Utils\Str;
|
||||||
|
|
||||||
|
@ -131,6 +132,7 @@ class ExampleRepository extends BaseRepository
|
||||||
// 根据主键ID查询数据
|
// 根据主键ID查询数据
|
||||||
// $this->find(2054, ['id', 'mobile']);
|
// $this->find(2054, ['id', 'mobile']);
|
||||||
|
|
||||||
|
|
||||||
// 主键查询没有就抛出错误
|
// 主键查询没有就抛出错误
|
||||||
// $this->findOrFail(20540000, ['id', 'mobile']);
|
// $this->findOrFail(20540000, ['id', 'mobile']);
|
||||||
|
|
||||||
|
@ -157,10 +159,11 @@ class ExampleRepository extends BaseRepository
|
||||||
// ], ['id', 'mobile'],true);
|
// ], ['id', 'mobile'],true);
|
||||||
|
|
||||||
// 分页获取数据
|
// 分页获取数据
|
||||||
// $this->paginate([
|
// $data = $this->paginate([
|
||||||
// 'id:gt' => 20540000,
|
// 'id:gt' => 2054,
|
||||||
// 'gender' => 2
|
// ], ['id', 'mobile'], 1, 5);
|
||||||
// ], ['*'], 1, 15);
|
//
|
||||||
|
// var_dump($data);
|
||||||
|
|
||||||
// 打印查询 sql 语句
|
// 打印查询 sql 语句
|
||||||
// $this->toSql([
|
// $this->toSql([
|
||||||
|
@ -181,6 +184,24 @@ class ExampleRepository extends BaseRepository
|
||||||
// ],
|
// ],
|
||||||
// ]
|
// ]
|
||||||
// ]);
|
// ]);
|
||||||
|
|
||||||
|
// 原生 SQL 查询
|
||||||
|
// $this->sql('SELECT * FROM `lar_users` WHERE id = ?', [2054]);
|
||||||
|
|
||||||
|
// 批量更新数据
|
||||||
|
// $this->batchUpdate([
|
||||||
|
// 'id:gt' => 2054
|
||||||
|
// ], [
|
||||||
|
// 'email' => '', // 不使用条件判断,默认更新
|
||||||
|
// 'gender' => [
|
||||||
|
// 'field' => 'id',//判断的字段,可选(不设置默认使用当前字段)
|
||||||
|
// 'default' => 0, // 默认字段值
|
||||||
|
// 'filter' => [ // 数据判断
|
||||||
|
// '2054' => 1,
|
||||||
|
// '2055' => 2,
|
||||||
|
// ]
|
||||||
|
// ],
|
||||||
|
// ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// where 条件查询案例
|
// where 条件查询案例
|
||||||
|
|
|
@ -0,0 +1,395 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Helper\ArrayHelper;
|
||||||
|
use Hyperf\Database\Model\Builder;
|
||||||
|
use Hyperf\Database\Model\Model;
|
||||||
|
use Hyperf\DbConnection\Db;
|
||||||
|
use Hyperf\Utils\Arr;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
trait RepositoryTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 自带查询的表达式
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $operators = [
|
||||||
|
'=',
|
||||||
|
'<',
|
||||||
|
'>',
|
||||||
|
'<=',
|
||||||
|
'>=',
|
||||||
|
'<>',
|
||||||
|
'!=',
|
||||||
|
'<=>',
|
||||||
|
'like',
|
||||||
|
'like binary',
|
||||||
|
'not like',
|
||||||
|
'ilike',
|
||||||
|
'&',
|
||||||
|
'|',
|
||||||
|
'^',
|
||||||
|
'<<',
|
||||||
|
'>>',
|
||||||
|
'rlike',
|
||||||
|
'regexp',
|
||||||
|
'not regexp',
|
||||||
|
'~',
|
||||||
|
'~*',
|
||||||
|
'!~',
|
||||||
|
'!~*',
|
||||||
|
'similar to',
|
||||||
|
'not similar to',
|
||||||
|
'not ilike',
|
||||||
|
'~~*',
|
||||||
|
'!~~*'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扩展查询的表达式
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $expression = [
|
||||||
|
'eq' => '=',
|
||||||
|
'neq' => '!=',
|
||||||
|
'ne' => '!=',
|
||||||
|
'gt' => '>',
|
||||||
|
'egt' => '>=',
|
||||||
|
'gte' => '>=',
|
||||||
|
'ge' => '>=',
|
||||||
|
'lt' => '<',
|
||||||
|
'le' => '<=',
|
||||||
|
'lte' => '<=',
|
||||||
|
'elt' => '<=',
|
||||||
|
'in' => 'In',
|
||||||
|
'not in' => 'NotIn',
|
||||||
|
'between' => 'Between',
|
||||||
|
'not between' => 'NotBetween',
|
||||||
|
'like' => 'like',
|
||||||
|
'not like' => 'not like',
|
||||||
|
'rlike' => 'rlike',
|
||||||
|
'<>' => '<>',
|
||||||
|
'<=>' => '<=>',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model 不需要查询条件的方法
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $origin = [
|
||||||
|
'create', 'insert', 'insertGetId',
|
||||||
|
'firstOrCreate', 'firstOrNew',
|
||||||
|
'updateOrCreate', 'updateOrInsert',
|
||||||
|
'findOrFail', 'findOrNew', 'find',
|
||||||
|
'getConnection',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父类需要查询条件的相关方法
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $parent = [
|
||||||
|
'count', 'max', 'min', 'avg', 'sum',
|
||||||
|
'increment', 'decrement',
|
||||||
|
'value', 'pluck',
|
||||||
|
'exists', 'doesntExist'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Model
|
||||||
|
*/
|
||||||
|
private $model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BaseRepository constructor.
|
||||||
|
* @param Model $model
|
||||||
|
*/
|
||||||
|
public function __construct(Model $model)
|
||||||
|
{
|
||||||
|
$this->model = $model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用 model 的方法
|
||||||
|
*
|
||||||
|
* @param string $method 调用model 自己的方法
|
||||||
|
* @param array $arguments
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function __call(string $method, array $arguments)
|
||||||
|
{
|
||||||
|
// 直接使用 model, 不需要查询条件的数据
|
||||||
|
if (in_array($method, $this->origin)) {
|
||||||
|
return (new $this->model)->{$method}(...$arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用 model 原生方法
|
||||||
|
if (in_array($method, $this->parent)) {
|
||||||
|
$where = Arr::pull($arguments, '0', []);
|
||||||
|
return $this->buildWhere($where)->{$method}(...$arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \Exception("Uncaught Error: Call to undefined method {$method}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取新的查询 Model
|
||||||
|
*
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
|
protected function getNewModel(): Builder
|
||||||
|
{
|
||||||
|
return $this->model->newQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建 Where 查询 Model
|
||||||
|
*
|
||||||
|
* @param array $where
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
|
final public function buildWhere(array $where = []): Builder
|
||||||
|
{
|
||||||
|
$model = $this->getNewModel();
|
||||||
|
|
||||||
|
// 处理排序数据
|
||||||
|
if ($order = Arr::pull($where, 'order by')) {
|
||||||
|
$this->addOrderBy($model, (array)$order);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理分组数据
|
||||||
|
if ($group = Arr::pull($where, 'group by')) {
|
||||||
|
$this->addGroupBy($model, (array)$group);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理分组数据
|
||||||
|
if ($having = Arr::pull($where, 'having by')) {
|
||||||
|
$this->addHaving($model, (array)$having);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否存在查询条件
|
||||||
|
if (!empty($where)) {
|
||||||
|
$this->bindWhere($model, $where);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Builder $model
|
||||||
|
* @param array $where
|
||||||
|
* @param bool $or
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function bindWhere(Builder $model, array $where, $or = false)
|
||||||
|
{
|
||||||
|
foreach ($where as $field => $item) {
|
||||||
|
if ($field === 'or' || $field === 'and') {
|
||||||
|
$this->addNewWhere($model, $item, $or, $field);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_int($field)) {
|
||||||
|
if ($this->isModelQueryArray($item)) {
|
||||||
|
$model->{$or ? 'orWhere' : 'where'}(...$item);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addNewWhere($model, $item, $or, $field);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字段查询
|
||||||
|
$this->setFieldWhere($model, $field, $item, $or);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加 where 条件分组
|
||||||
|
*
|
||||||
|
* @param Builder $model
|
||||||
|
* @param array $where
|
||||||
|
* @param bool $or
|
||||||
|
* @param string $field
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function addNewWhere(Builder $model, array $where, $or = false, $field = '')
|
||||||
|
{
|
||||||
|
$method = $or ? 'orWhere' : 'where';
|
||||||
|
|
||||||
|
$model->{$method}(function ($query) use ($where, $or, $field) {
|
||||||
|
$this->bindWhere($query, $where, $field === 'or');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加排序信息
|
||||||
|
*
|
||||||
|
* @param Builder $model
|
||||||
|
* @param array $orders
|
||||||
|
*/
|
||||||
|
private function addOrderBy(Builder $model, array $orders)
|
||||||
|
{
|
||||||
|
foreach ($orders as $field => $sort) {
|
||||||
|
if ($this->isBackQuote($field)) {
|
||||||
|
$model->orderByRaw($this->trimBackQuote($field) . ' ' . $sort);
|
||||||
|
} else {
|
||||||
|
$model->orderBy($field, $sort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加分组信息
|
||||||
|
*
|
||||||
|
* @param Builder $model
|
||||||
|
* @param array $groups
|
||||||
|
*/
|
||||||
|
private function addGroupBy(Builder $model, array $groups)
|
||||||
|
{
|
||||||
|
$model->groupBy(...$groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Builder $model
|
||||||
|
* @param array $items
|
||||||
|
*/
|
||||||
|
private function addHaving(Builder $model, array $items = [])
|
||||||
|
{
|
||||||
|
foreach ($items as $having) {
|
||||||
|
$model->{count($having) == 2 ? 'havingRaw' : 'having'}(...$having);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置条件查询
|
||||||
|
*
|
||||||
|
* @param Builder $model
|
||||||
|
* @param string $field
|
||||||
|
* @param string|int|array $value
|
||||||
|
* @param bool $or
|
||||||
|
* @return void
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
private function setFieldWhere(Builder $model, string $field, $value, $or = false): void
|
||||||
|
{
|
||||||
|
[$field, $operator] = $this->formatField($field);
|
||||||
|
|
||||||
|
// 查询数据是数组且未设置表达式,默认是 In 查询
|
||||||
|
if ($operator === 'eq' && is_array($value)) {
|
||||||
|
$operator = 'in';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证查询表达式
|
||||||
|
if (!isset($this->expression[$operator])) {
|
||||||
|
throw new \Exception("无效的 {$operator} 操作符!");
|
||||||
|
}
|
||||||
|
|
||||||
|
$method = $or ? 'orWhere' : 'where';
|
||||||
|
|
||||||
|
// 数组查询方式
|
||||||
|
if (in_array($this->expression[$operator], ['In', 'NotIn', 'Between', 'NotBetween'], true)) {
|
||||||
|
$method = $method . $this->expression[$operator];
|
||||||
|
$model->{$method}($field, (array)$value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$model->{$method}($field, $this->expression[$operator], $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析查询字段信息
|
||||||
|
*
|
||||||
|
* @param string $field 查询字段
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function formatField(string $field): array
|
||||||
|
{
|
||||||
|
$item = explode(':', $field);
|
||||||
|
$field = $item[0];
|
||||||
|
$operator = $item[1] ?? 'eq';
|
||||||
|
|
||||||
|
return [strtolower($field), trim($operator)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理查询字段
|
||||||
|
*
|
||||||
|
* @param array $fields 查询字段
|
||||||
|
*/
|
||||||
|
private function handleField(array &$fields)
|
||||||
|
{
|
||||||
|
foreach ($fields as $k => $field) {
|
||||||
|
$fields[$k] = $this->raw($field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 去除字段串两端反引号
|
||||||
|
*
|
||||||
|
* @param string $field
|
||||||
|
* @return \Hyperf\Database\Query\Expression|string
|
||||||
|
*/
|
||||||
|
private function raw(string $field)
|
||||||
|
{
|
||||||
|
// 匹配使用反引号的字段
|
||||||
|
if (!$this->isBackQuote($field)) return $field;
|
||||||
|
|
||||||
|
return Db::raw($this->trimBackQuote($field));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断字符串是否被反引号包含
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isBackQuote(string $string): bool
|
||||||
|
{
|
||||||
|
return (bool)preg_match("/^`.*?`$/", $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 去除字符串两端的反引号
|
||||||
|
*
|
||||||
|
* @param string $field
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function trimBackQuote(string $field): string
|
||||||
|
{
|
||||||
|
return substr($field, 1, strlen($field) - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否是调用 where 最基本的方式是需要传递三个参数
|
||||||
|
*
|
||||||
|
* @param array $items
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isModelQueryArray(array $items): bool
|
||||||
|
{
|
||||||
|
if (count($items) != 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否是关联数组
|
||||||
|
if (ArrayHelper::isRelationArray($items)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($items as $item) {
|
||||||
|
if (is_array($item)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return in_array($items[1], $this->operators);
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,8 +37,7 @@
|
||||||
"hyperf/view-engine": "2.1.*",
|
"hyperf/view-engine": "2.1.*",
|
||||||
"phpmailer/phpmailer": "^6.2",
|
"phpmailer/phpmailer": "^6.2",
|
||||||
"96qbhy/hyperf-auth": "^2.3",
|
"96qbhy/hyperf-auth": "^2.3",
|
||||||
"hyperf/event": "2.1.*",
|
"hyperf/event": "2.1.*"
|
||||||
"hyperf/paginator": "2.1.*"
|
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"swoole/ide-helper": "^4.5",
|
"swoole/ide-helper": "^4.5",
|
||||||
|
|
Loading…
Reference in New Issue