building-sign/app/service/Repository.php

307 lines
9.2 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace app\service;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;
use think\facade\Db;
use think\Collection;
use think\facade\Env;
use think\facade\Log;
use think\Paginator;
use app\exception\RepositoryException;
/**
* 领域模型-仓储
*
* Class Repository
* @package app\service
*/
class Repository
{
/**
* @var array 已加载对象列表
*/
private static $objects = [];
/**
* @var Model 模型对象
*/
protected $model;
// 布尔值数字关系
public const BOOL_FALSE = 0;
public const BOOL_TRUE = 1;
/**
* 获取当前子对象实列(单例形式返回)
*
* @param Model|null $model 模型对象。未指定则自动获取
* @return mixed
*/
public static function getInstance(Model $model = null)
{
$class = get_called_class();
if (isset(self::$objects[$class]) && self::$objects[$class] !== null) {
return self::$objects[$class];
}
$obj = new $class();
if ($model) {
$obj->model = $model;
} elseif (strpos($class, '\\repository') > 0) {
$model = str_replace('\\repository', '\\model', $class);
//去掉末尾Repository app\model\AccountRepository =》 app\model\Account
$model = substr($model, 0, strlen($model) - strlen('Repository'));
if (class_exists($model)) {
$obj->model = new $model;
}
}
self::$objects[$class] = $obj;
return $obj;
}
/**
* @param callable $callback
* @param mixed $failReturn
* @param bool $transaction
* @return mixed
* @throws RepositoryException
*/
protected function access(callable $callback, $failReturn, bool $transaction = false)
{
$exception = null;
try {
if ($transaction) {
Db::startTrans();
}
$r = $callback();
if ($transaction) {
Db::commit();
}
if ($r) {
return $r;
}
if ($failReturn instanceof Exception) {
return null;
}
return $failReturn;
} catch (Exception $e) {
if ($transaction) {
Db::rollback();
}
if ($e instanceof RepositoryException) {
throw $e;
}
$name = 'Domain - Repository - 未知错误';
$traces = $e->getTrace();
foreach ($traces as $i => $trace) {
if (!empty($trace['class']) && $trace['class'] === Repository::class && $trace['function'] === 'access') {
$trace = $traces[$i - 2] ?? null;
break;
}
}
if (!empty($trace) && !empty($trace['file'][1]) && !empty($trace['line'])) {
$parts = explode('application\\', $trace['file']);
if (!empty($parts[1])) {
$name = $parts[1].':'.$trace['line'];
} else {
$name = $trace['file'].':'.$trace['line'];
}
}
$exception = $e;
$line = '['.$name.'] '.$e->getMessage();
Log::error($line);
throw new RepositoryException('Repository异常'.(Env::get('app_debug') ? ': '.$line : ''), 5009);
} finally {
if ($exception && $failReturn instanceof RepositoryException) {
if (Env::get('app_debug')) {
$failReturn = new RepositoryException($failReturn->getMessage().': '.$exception->getMessage(),
$failReturn->getCode());
}
throw $failReturn;
}
}
}
/**
* 获取当前model对象
*
* @return Model
*/
public function getModel(): Model
{
return $this->model;
}
/**
* 根据条件查询列表
*
* @param array $where 查询条件
* @param array $fields 查询字段 []表示全部
* @param int $page 默认第一页 0不限制
* @param int $limit 限制条数 0不限制
* @param callable|null $callback 更为复杂的条件 使用闭包查询
* @return array
* @throws RepositoryException
*/
public function findList(array $where = [], array $fields = [], int $page = 1, int $limit = 0, callable $callback = null, array $order = []): ?array
{
$failData = [
'total' => 0,
'current' => $page,
'size' => $limit,
'list' => new Collection(),
];
return $this->access(function () use ($where, $fields, $page, $limit, $callback, $order) {
return $this->model->findList($where, $fields, $page, $limit, $callback, $order);
}, $failData);
}
/**
* 根据条件查询列表[带分页 适用于后台]
*
* @param array $data 查询数据
* @param array $pageParams 分页参数
* @param callable|null $callback 复杂查询条件 使用闭包查询
* @return Paginator
*/
public function findListWithPaginate(array $data = [], array $pageParams = [], callable $callback = null): Paginator
{
return $this->model->findListWithPaginate($data, $pageParams, $callback);
}
/**
* 根据主键 ID 查询
*
* @param int $id ID
* @param array $fields 要返回的字段,默认全部
* @return Mixed
* @throws RepositoryException
*/
public function findById(int $id, array $fields = [], callable $callback = null)
{
return $this->access(function () use ($id, $fields, $callback) {
return $this->model->findById($id, $fields, $callback);
}, null);
}
/**
* @param array $where
* @param array $fields
* @return array|Model|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function findOneByWhere(array $where, array $fields = [])
{
return $this->model->field($fields)->where($where)->find();
}
/**
* 创建
*
* @param array $data 数据
* @return Model
* @throws RepositoryException
*/
public function create(array $data): Model
{
return $this->access(function () use ($data) {
return $this->model->create($data);
}, new RepositoryException('创建失败'));
}
/**
* 更新
*
* @param array $data 数据
* @param array $where 条件
* @return bool|Exception
* @throws RepositoryException
*/
public function update(array $data, array $where): bool
{
return $this->access(function () use ($data, $where) {
return $this->model->where($where)->find()->save($data);
}, new RepositoryException('更新失败'));
}
/**
* 删除
*
* @param array $where 删除条件
* @param bool $softDelete 是否软删除 默认false
* @param string $softDeleteTime 删除时间 softDelete=true时有效
* @param string $softDeleteField 软删除字段 softDelete=true时有效
* @return bool
* @throws RepositoryException
*/
public function delete(array $where, bool $softDelete = false, string $softDeleteTime = '', string $softDeleteField = 'deleted_at'): bool
{
return $this->access(function () use ($where, $softDelete, $softDeleteField, $softDeleteTime) {
// 注意如果model中引入了软删除trait$softDelete又设置false 将无法正确删除
return $this->model->where($where)
->when($softDelete, function ($q) use ($softDeleteField, $softDeleteTime) {
$softDeleteTime = $softDeleteTime ?: date('Y-m-d H:i:s');
$q->useSoftDelete($softDeleteField, $softDeleteTime);
})->delete();
}, false);
}
/**
* 排序
*
* @param int $id 排序ID
* @param string $type 排序类型 向上、向下
* @param int $num 移动位数
* @param string $listType 列表的排序类型 降序|升序
* @param array $where 额外条件 格式如:
* $map[] = ['name','like','think'];
* $map[] = ['status','=',1];
* @return array
*/
public function sort(int $id,string $type,int $num,string $listType, array $where = []): array
{
return $this->model->sort($id, $type, $num, $listType, $where);
}
/**
* 日志记录
*
* @param string $msg
* @param Exception|null $e
* @param string $level
* @param string $channel
*/
public static function log(string $msg, Exception $e = null, string $level = 'error', string $channel = 'file')
{
if ($e != null) {
$msg = sprintf("[%s]%s:%s %s", $msg, $e->getFile(), $e->getLine(), $e->getMessage());
} else {
$msg = sprintf("%s", $msg);
}
Log::channel($channel)->$level($msg);
}
}