..
This commit is contained in:
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Aether;
|
||||
|
||||
use Aether\Contract\TreeableInterface;
|
||||
use Closure;
|
||||
use DateTime;
|
||||
use Exception;
|
||||
@@ -91,6 +92,60 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表查询.
|
||||
*/
|
||||
// public function list(array $params = []): array
|
||||
// {
|
||||
// $query = $this->newQuery();
|
||||
//
|
||||
// // 通过模型配置自动应用所有搜索条件
|
||||
// $this->applySearch($query, $params);
|
||||
//
|
||||
// // 动态应用排序
|
||||
// $sortConfig = $this->getSortConfig();
|
||||
// if ($sortConfig) {
|
||||
// $query->orderBy($sortConfig['field'], $sortConfig['direction']);
|
||||
// }
|
||||
//
|
||||
// $withDeleted = filter_var($params['with_deleted'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
||||
// if ($withDeleted) {
|
||||
// $query->withTrashed();
|
||||
// }
|
||||
//
|
||||
// // 存在分页参数(page或size)则进行分页查询
|
||||
// if (isset($params['page']) || isset($params['size'])) {
|
||||
// $page = (int) ($params['page'] ?? 1);
|
||||
// $size = (int) ($params['size'] ?? 10);
|
||||
// $page = max(1, $page);
|
||||
// $size = max(1, min(100, $size));
|
||||
// $result = $query->paginate($size, ['*'], 'page', $page);
|
||||
// return [
|
||||
// 'total' => $result->total(),
|
||||
// 'list' => $result->items(),
|
||||
// ];
|
||||
// }
|
||||
//
|
||||
// // 无分页参数时返回完整数据集合
|
||||
// $items = $query->get()->toArray();
|
||||
//
|
||||
// // 若模型支持树形结构则构建树形,否则返回普通数组
|
||||
// if ($this instanceof TreeableInterface) {
|
||||
// return $this::buildTree($items, (int) ($params['parent_id'] ?? 0));
|
||||
// }
|
||||
//
|
||||
// return $items;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 列表查询.
|
||||
*/
|
||||
public function list(array $params = []): array
|
||||
{
|
||||
$query = $this->buildQueryFromParams($params);
|
||||
return $this->listResult($query, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 快捷创建.
|
||||
*/
|
||||
@@ -238,6 +293,76 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface
|
||||
return Db::transaction($closure);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参数构建查询.
|
||||
*/
|
||||
protected function buildQueryFromParams(array $params = []): Builder
|
||||
{
|
||||
// 创建查询构建器
|
||||
$query = static::query();
|
||||
|
||||
// 应用搜索条件
|
||||
// if (isset($params['search'])) {
|
||||
// $this->applySearch($query, $params['search']);
|
||||
// }
|
||||
$this->applySearch($query, $params);
|
||||
// 应用排序
|
||||
$this->applySorting($query, $params);
|
||||
|
||||
// 处理软删除
|
||||
if (isset($params['withTrashed']) && $params['withTrashed']) {
|
||||
$query->withTrashed();
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用排序.
|
||||
*/
|
||||
protected function applySorting(Builder $query, array $params = []): void
|
||||
{
|
||||
// 优先使用传入的排序参数
|
||||
if (isset($params['sort_field'], $params['sort_direction'])) {
|
||||
$query->orderBy($params['sort_field'], $params['sort_direction']);
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用模型配置的排序
|
||||
$sortConfig = $this->getSortConfig();
|
||||
if (! empty($sortConfig)) {
|
||||
$query->orderBy($sortConfig['field'], $sortConfig['direction']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分页参数获取结果.
|
||||
*/
|
||||
protected function listResult(Builder $query, array $params = []): array
|
||||
{
|
||||
// 分页处理
|
||||
if (isset($params['page'], $params['size'])) {
|
||||
$page = max(1, (int) $params['page']);
|
||||
$size = max(1, min(100, (int) $params['size']));
|
||||
$result = $query->paginate($size, ['*'], 'page', $page);
|
||||
|
||||
return [
|
||||
'list' => $result->items(),
|
||||
'total' => $result->total(),
|
||||
];
|
||||
}
|
||||
|
||||
// 获取所有数据
|
||||
$result = $query->get()->toArray();
|
||||
|
||||
// 如果实现了树结构接口,构建树
|
||||
if ($this instanceof TreeableInterface) {
|
||||
return $this->buildTree($result, $params['parent_id'] ?? 0);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化模型.
|
||||
*/
|
||||
|
||||
@@ -4,38 +4,105 @@ declare(strict_types=1);
|
||||
|
||||
namespace Aether;
|
||||
|
||||
use Hyperf\Context\ApplicationContext;
|
||||
use Hyperf\Context\Context;
|
||||
use Hyperf\ExceptionHandler\ExceptionHandler;
|
||||
use Hyperf\Rpc\Protocol;
|
||||
use Hyperf\HttpMessage\Stream\SwooleStream;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
|
||||
use function Hyperf\Support\env;
|
||||
|
||||
class RpcExceptionHandler extends ExceptionHandler
|
||||
{
|
||||
/**
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
public function handle(Throwable $throwable, ResponseInterface $response): ResponseInterface
|
||||
{
|
||||
// 微服务间调用返回更精简的错误信息
|
||||
$data = [
|
||||
'code' => $throwable->getCode() ?: 500,
|
||||
'message' => $throwable->getMessage() ?: '服务调用失败',
|
||||
'request_id' => Context::get('request_id', ''),
|
||||
];
|
||||
try {
|
||||
// 获取请求ID(用于日志追踪)
|
||||
$requestId = Context::get('request_id', '');
|
||||
|
||||
$protocol = ApplicationContext::getContainer()->get(Protocol::class);
|
||||
$response->getBody()->write($protocol->pack($data));
|
||||
// 从请求中获取可能的RPC ID
|
||||
$rpcId = $this->getRpcIdFromRequest();
|
||||
|
||||
return $response;
|
||||
// 构建符合JSON-RPC 2.0规范的错误响应
|
||||
$errorResponse = [
|
||||
'jsonrpc' => '2.0',
|
||||
'id' => $rpcId ?? $requestId,
|
||||
'error' => [
|
||||
'code' => $throwable->getCode() ?: -32603, // 默认服务器错误码
|
||||
'message' => $throwable->getMessage() ?: 'Internal error',
|
||||
'data' => [
|
||||
'request_id' => $requestId,
|
||||
'exception_type' => get_class($throwable),
|
||||
// 开发环境下可以添加更多调试信息
|
||||
'debug' => env('APP_ENV') === 'dev' ? [
|
||||
'file' => $throwable->getFile(),
|
||||
'line' => $throwable->getLine(),
|
||||
] : null,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// JSON编码
|
||||
$jsonResponse = json_encode($errorResponse, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
// 检查JSON编码错误
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
$jsonResponse = json_encode([
|
||||
'jsonrpc' => '2.0',
|
||||
'id' => $rpcId ?? $requestId,
|
||||
'error' => [
|
||||
'code' => -32603,
|
||||
'message' => 'Failed to encode error response',
|
||||
'data' => ['request_id' => $requestId],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
return $response
|
||||
->withHeader('Content-Type', 'application/json')
|
||||
->withBody(new SwooleStream((string) $jsonResponse));
|
||||
} catch (Throwable $e) {
|
||||
$fallbackResponse = json_encode([
|
||||
'jsonrpc' => '2.0',
|
||||
'id' => null,
|
||||
'error' => [
|
||||
'code' => -32603,
|
||||
'message' => 'Fatal error occurred in exception handler',
|
||||
'data' => ['original_error' => $throwable->getMessage()],
|
||||
],
|
||||
]);
|
||||
|
||||
return $response
|
||||
->withHeader('Content-Type', 'application/json')
|
||||
->withBody(new SwooleStream((string) $fallbackResponse));
|
||||
}
|
||||
}
|
||||
|
||||
public function isValid(Throwable $throwable): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试从请求中获取RPC ID.
|
||||
*/
|
||||
private function getRpcIdFromRequest(): mixed
|
||||
{
|
||||
try {
|
||||
$request = Context::get('hyperf.request');
|
||||
if ($request) {
|
||||
$body = $request->getParsedBody();
|
||||
if (is_array($body) && isset($body['id'])) {
|
||||
return $body['id'];
|
||||
}
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
// 获取失败时静默处理
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MicroService\Contract;
|
||||
|
||||
interface DataServiceInterface
|
||||
{
|
||||
// ----------------- 校区服务 -----------------
|
||||
|
||||
public function getCampuses(array $data): array;
|
||||
|
||||
public function getCampusBy(int $id): array;
|
||||
|
||||
public function createCampus(array $data): int;
|
||||
|
||||
public function updateCampus(int $id, array $data): int;
|
||||
|
||||
public function deleteCampus(int $id): bool;
|
||||
|
||||
/**
|
||||
* 获取校区详情.
|
||||
* @param int $id 校区ID
|
||||
@@ -36,6 +49,16 @@ interface DataServiceInterface
|
||||
|
||||
// ----------------- 教师服务 -----------------
|
||||
|
||||
public function getTeachers(): array;
|
||||
|
||||
public function getTeacherBy(int $id): array;
|
||||
|
||||
public function createTeacher(array $data): int;
|
||||
|
||||
public function updateTeacher(int $id, array $data): int;
|
||||
|
||||
public function deleteTeacher(int $id): bool;
|
||||
|
||||
/**
|
||||
* 获取教师详情.
|
||||
* @param int $id 教师ID
|
||||
@@ -71,4 +94,4 @@ interface DataServiceInterface
|
||||
* @param int $size 每页条数
|
||||
*/
|
||||
public function searchTeachers(string $keyword, int $page = 1, int $size = 20): array;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user