270 lines
6.7 KiB
PHP
270 lines
6.7 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
|
||
use App\Exceptions\BusinessException;
|
||
use App\Helpers\ResponseEnum;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
use Illuminate\Pagination\LengthAwarePaginator;
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
/**
|
||
* 基础服务类
|
||
*/
|
||
abstract class BaseService
|
||
{
|
||
/**
|
||
* 模型实例
|
||
*/
|
||
protected Model $model;
|
||
|
||
/**
|
||
* 模型类名
|
||
*/
|
||
protected string $modelClass;
|
||
|
||
public function __construct()
|
||
{
|
||
if (isset($this->modelClass)) {
|
||
$this->model = new $this->modelClass();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建记录
|
||
*/
|
||
public function create(array $data): Model
|
||
{
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
// 验证唯一性
|
||
$this->validateUnique($data);
|
||
|
||
// 过滤字段
|
||
$filteredData = $this->filterFields($data);
|
||
|
||
// 创建记录(BaseModel会自动设置系统字段)
|
||
$model = $this->modelClass::create($filteredData);
|
||
|
||
DB::commit();
|
||
return $model;
|
||
|
||
} catch (BusinessException $e) {
|
||
DB::rollBack();
|
||
throw $e;
|
||
} catch (\Exception $e) {
|
||
DB::rollBack();
|
||
throw new BusinessException(ResponseEnum::DATA_INSERT_ERROR, $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新记录
|
||
*/
|
||
public function update(int $id, array $data): Model
|
||
{
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
$model = $this->findById($id);
|
||
|
||
// 验证租户权限
|
||
if (!$model->validateTenantAccess()) {
|
||
throw new BusinessException(ResponseEnum::CLIENT_HTTP_UNAUTHORIZED, '无权限访问该数据');
|
||
}
|
||
|
||
// 验证唯一性(排除当前记录)
|
||
$this->validateUnique($data, $id);
|
||
|
||
// 过滤字段
|
||
$filteredData = $this->filterFields($data);
|
||
|
||
// 更新记录(BaseModel会自动设置更新字段)
|
||
$model->update($filteredData);
|
||
|
||
DB::commit();
|
||
return $model;
|
||
|
||
} catch (BusinessException $e) {
|
||
DB::rollBack();
|
||
throw $e;
|
||
} catch (\Exception $e) {
|
||
DB::rollBack();
|
||
throw new BusinessException(ResponseEnum::DATA_UPDATE_ERROR, $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 删除记录
|
||
*/
|
||
public function delete(int $id): bool
|
||
{
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
$model = $this->findById($id);
|
||
|
||
// 验证租户权限
|
||
if (!$model->validateTenantAccess()) {
|
||
throw new BusinessException(ResponseEnum::CLIENT_HTTP_UNAUTHORIZED, '无权限访问该数据');
|
||
}
|
||
|
||
$result = $model->delete();
|
||
|
||
DB::commit();
|
||
return $result;
|
||
|
||
} catch (BusinessException $e) {
|
||
DB::rollBack();
|
||
throw $e;
|
||
} catch (\Exception $e) {
|
||
DB::rollBack();
|
||
throw new BusinessException(ResponseEnum::DATA_DELETE_ERROR, $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 批量删除记录
|
||
*/
|
||
public function batchDelete(array $ids): bool
|
||
{
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
if (empty($ids)) {
|
||
throw new BusinessException(ResponseEnum::CLIENT_PARAMETER_ERROR, 'ID列表不能为空');
|
||
}
|
||
|
||
// 验证所有记录的租户权限
|
||
$models = $this->modelClass::whereIn('id', $ids)->get();
|
||
|
||
foreach ($models as $model) {
|
||
if (!$model->validateTenantAccess()) {
|
||
throw new BusinessException(ResponseEnum::CLIENT_HTTP_UNAUTHORIZED, '无权限访问部分数据');
|
||
}
|
||
}
|
||
|
||
$deleteCount = $this->modelClass::whereIn('id', $ids)->delete();
|
||
|
||
if ($deleteCount === 0) {
|
||
throw new BusinessException(ResponseEnum::DATA_NOT_FOUND_ERROR);
|
||
}
|
||
|
||
DB::commit();
|
||
return true;
|
||
|
||
} catch (BusinessException $e) {
|
||
DB::rollBack();
|
||
throw $e;
|
||
} catch (\Exception $e) {
|
||
DB::rollBack();
|
||
throw new BusinessException(ResponseEnum::DATA_DELETE_ERROR, $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取记录详情
|
||
*/
|
||
public function detail(int $id): Model
|
||
{
|
||
$model = $this->findById($id);
|
||
|
||
// 验证租户权限
|
||
if (!$model->validateTenantAccess()) {
|
||
throw new BusinessException(ResponseEnum::CLIENT_HTTP_UNAUTHORIZED, '无权限访问该数据');
|
||
}
|
||
|
||
return $model;
|
||
}
|
||
|
||
/**
|
||
* 获取记录列表(基础版)
|
||
*/
|
||
public function list(array $params): LengthAwarePaginator
|
||
{
|
||
$page = (int)($params['page'] ?? 1);
|
||
$pageSize = (int)($params['page_size'] ?? 15);
|
||
|
||
// 使用模型的全局作用域自动过滤租户数据
|
||
$query = $this->modelClass::query();
|
||
|
||
// 子类可以重写此方法来添加特定的搜索条件
|
||
$this->applySearchConditions($query, $params);
|
||
|
||
// 添加排序
|
||
$query->ordered();
|
||
|
||
return $query->paginate($pageSize, ['*'], 'page', $page);
|
||
}
|
||
|
||
/**
|
||
* 应用搜索条件(子类重写此方法)
|
||
*/
|
||
protected function applySearchConditions($query, array $params): void
|
||
{
|
||
// 默认不添加任何搜索条件,子类可以重写
|
||
}
|
||
|
||
/**
|
||
* 根据ID查找记录
|
||
*/
|
||
protected function findById(int $id): Model
|
||
{
|
||
// 使用模型的全局作用域自动过滤租户数据
|
||
$model = $this->modelClass::find($id);
|
||
|
||
if (!$model) {
|
||
throw new BusinessException(ResponseEnum::DATA_NOT_FOUND_ERROR);
|
||
}
|
||
|
||
return $model;
|
||
}
|
||
|
||
/**
|
||
* 验证唯一性(子类重写此方法)
|
||
*/
|
||
protected function validateUnique(array $data, ?int $excludeId = null): void
|
||
{
|
||
// 默认不验证唯一性,子类可以重写
|
||
}
|
||
|
||
/**
|
||
* 过滤字段
|
||
*/
|
||
protected function filterFields(array $data): array
|
||
{
|
||
$fillable = $this->model->getFillable();
|
||
|
||
return array_filter(
|
||
array_intersect_key($data, array_flip($fillable)),
|
||
function ($value) {
|
||
return $value !== null && $value !== '';
|
||
}
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 获取当前租户ID
|
||
*/
|
||
protected function getCurrentTenantId(): ?int
|
||
{
|
||
$user = auth('admin')->user();
|
||
return $user ? $user->tenant_id : null;
|
||
}
|
||
|
||
/**
|
||
* 验证租户权限
|
||
*/
|
||
protected function validateTenantAccess(?int $tenantId): bool
|
||
{
|
||
$currentTenantId = $this->getCurrentTenantId();
|
||
|
||
if ($currentTenantId === null) {
|
||
return false;
|
||
}
|
||
|
||
return $tenantId == $currentTenantId;
|
||
}
|
||
}
|