diff --git a/extend/Aether/PHP/Hyperf/AetherController.php b/extend/Aether/PHP/Hyperf/AetherController.php index 5d502e3..f5bf9c9 100644 --- a/extend/Aether/PHP/Hyperf/AetherController.php +++ b/extend/Aether/PHP/Hyperf/AetherController.php @@ -20,9 +20,8 @@ abstract class AetherController #[Inject] protected ResponseInterface $response; - /** - * 获取资源列表 (RESTFul: GET /resources) + * 获取资源列表 (RESTFul: GET resources/list). */ public function index(): array { @@ -32,7 +31,7 @@ abstract class AetherController } /** - * 获取单个资源 (RESTFul: GET /resources/{id}) + * 获取单个资源 (RESTFul: GET resources/{id}). */ public function detail(int $id): array { @@ -41,7 +40,7 @@ abstract class AetherController } /** - * 创建资源 (RESTFul: POST /resources) + * 创建资源 (RESTFul: POST resources). */ public function create(): array { @@ -51,7 +50,7 @@ abstract class AetherController } /** - * 更新资源 (RESTFul: PUT /resources/{id}) + * 更新资源 (RESTFul: PUT resources/{id}). */ public function update(int $id): array { @@ -61,7 +60,7 @@ abstract class AetherController } /** - * 删除资源 (RESTFul: DELETE /resources/{id}) + * 删除资源 (RESTFul: DELETE resources/{id}). */ public function delete(int $id): array { @@ -70,8 +69,7 @@ abstract class AetherController } /** - * 获取对应的服务类 - * @return AetherCrudService + * 获取对应的服务类. */ abstract protected function getService(): AetherCrudService; } diff --git a/extend/Aether/PHP/Hyperf/AetherCrudService.php b/extend/Aether/PHP/Hyperf/AetherCrudService.php index 03e8926..51cc6ef 100644 --- a/extend/Aether/PHP/Hyperf/AetherCrudService.php +++ b/extend/Aether/PHP/Hyperf/AetherCrudService.php @@ -18,20 +18,10 @@ use Throwable; */ abstract class AetherCrudService extends AetherService implements AetherCrudInterface { - #[Inject] - protected LoggerFactory $loggerFactory; - - protected LoggerInterface $logger; - protected array $search = []; protected array $ignoreSearchFields = []; - public function __construct() - { - $this->logger = $this->loggerFactory->get($this->getLoggerName()); - } - /** * 通用列表查询(支持分页和树形结构). */ @@ -85,7 +75,6 @@ abstract class AetherCrudService extends AetherService implements AetherCrudInte */ public function detail(int $id): object { - $this->logger->info('获取资源详情', ['id' => $id]); return $this->getModel()->findOrFailById($id); } @@ -262,14 +251,6 @@ abstract class AetherCrudService extends AetherService implements AetherCrudInte }); } - /** - * 获取日志名称. - */ - protected function getLoggerName(): string - { - return strtolower((new ReflectionClass($this))->getShortName()); - } - protected function getSearch(): array { return $this->search; diff --git a/extend/Aether/PHP/Hyperf/AetherModel.php b/extend/Aether/PHP/Hyperf/AetherModel.php index c9c9087..e614f6c 100644 --- a/extend/Aether/PHP/Hyperf/AetherModel.php +++ b/extend/Aether/PHP/Hyperf/AetherModel.php @@ -12,8 +12,8 @@ use Hyperf\Contract\LengthAwarePaginatorInterface; use Hyperf\Database\Model\Builder; use Hyperf\Database\Model\Collection; use Hyperf\Database\Model\ModelNotFoundException; -use Hyperf\DbConnection\Model\Model as HyperfModel; use Hyperf\DbConnection\Db; +use Hyperf\DbConnection\Model\Model as HyperfModel; use Hyperf\HttpServer\Contract\RequestInterface; use Hyperf\ModelCache\Cacheable; use Hyperf\ModelCache\CacheableInterface; @@ -60,13 +60,19 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface * 排序配置: * - false: 禁用排序 * - 字符串: 排序字段(默认升序) - * - 数组: ['field' => '字段名', 'direction' => 'asc/desc'] + * - 数组: ['field' => '字段名', 'direction' => 'asc/desc']. */ - protected string|array|bool $sortable = 'sort'; // 默认按sort字段升序 + protected array|bool|string $sortable = 'sort'; // 默认按sort字段升序 + + public function __construct(array $attributes = []) + { + parent::__construct($attributes); + $this->bootBaseModel(); + } /** - * 获取排序配置 - * @return array|null [field, direction] 或 null(禁用排序) + * 获取排序配置. + * @return null|array [field, direction] 或 null(禁用排序) */ public function getSortConfig(): ?array { @@ -78,19 +84,13 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface if (is_string($this->sortable)) { return [ 'field' => $this->sortable, - 'direction' => 'asc' + 'direction' => 'asc', ]; } return null; } - public function __construct(array $attributes = []) - { - parent::__construct($attributes); - $this->bootBaseModel(); - } - /** * 快捷创建. */ @@ -108,7 +108,7 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface } /** - * 快捷删除指定ID的记录 + * 快捷删除指定ID的记录. * * @param int $id 要删除的记录ID * @return bool 成功删除返回true @@ -117,19 +117,18 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface */ public static function deleteById(int $id): bool { - if (!static::query()->where('id', $id)->exists()) { + if (! static::query()->where('id', $id)->exists()) { throw new ModelNotFoundException(sprintf( - '找不到ID为 %d 的 %s 记录', - $id, - static::class - )); + '找不到ID为 %d 的 %s 记录', + $id, + static::class + )); } return static::query()->where('id', $id)->delete() > 0; } /** * 快捷查找. - * @param int $id * @return Builder|Builder[]|Collection|HyperfModel * @throws Exception 当删除操作发生其他错误时抛出 * @throws ModelNotFoundException @@ -147,21 +146,21 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface * 快捷查找或失败. * @param int $id 要查找的记录ID * @return AetherModel 根据ID查找记录,不存在则抛出异常 - * 根据ID查找记录,不存在则抛出异常 + * 根据ID查找记录,不存在则抛出异常 * @throws Exception 当删除操作发生其他错误时抛出 * @throws ModelNotFoundException 当记录不存在时抛出 */ public static function findOrFailById(int $id): static { $record = static::query()->find($id); - if(is_null($record)) { + if (is_null($record)) { throw new ModelNotFoundException(sprintf( '找不到ID为 %d 的 %s 记录', $id, static::class )); } - return $record;// static::query()->findOrFail($id); + return $record; // static::query()->findOrFail($id); } /** @@ -406,7 +405,7 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface { foreach ($conditions as $field => $value) { // 跳过非字符串的字段名(防止索引数组键导致的类型错误) - if (!is_string($field)) { + if (! is_string($field)) { continue; } diff --git a/extend/Aether/PHP/Hyperf/ApiExceptionHandler.php b/extend/Aether/PHP/Hyperf/ApiExceptionHandler.php index 5fb5e1e..9a7a70a 100644 --- a/extend/Aether/PHP/Hyperf/ApiExceptionHandler.php +++ b/extend/Aether/PHP/Hyperf/ApiExceptionHandler.php @@ -4,13 +4,14 @@ declare(strict_types=1); namespace Aether; -use function Hyperf\Support\env; +use Hyperf\Context\Context; use Hyperf\ExceptionHandler\ExceptionHandler; use Hyperf\HttpMessage\Stream\SwooleStream; use Psr\Http\Message\MessageInterface; use Psr\Http\Message\ResponseInterface; use Throwable; -use Hyperf\Context\Context; + +use function Hyperf\Support\env; class ApiExceptionHandler extends ExceptionHandler { @@ -39,4 +40,4 @@ class ApiExceptionHandler extends ExceptionHandler { return true; } -} \ No newline at end of file +} diff --git a/extend/Aether/PHP/Hyperf/Contract/TreeableInterface.php b/extend/Aether/PHP/Hyperf/Contract/TreeableInterface.php index 78bedbe..bf31f94 100644 --- a/extend/Aether/PHP/Hyperf/Contract/TreeableInterface.php +++ b/extend/Aether/PHP/Hyperf/Contract/TreeableInterface.php @@ -1,24 +1,24 @@ withBody(new SwooleStream(json_encode($result, JSON_UNESCAPED_UNICODE))); } + public function isValid(Throwable $throwable): bool + { + return true; + } + private function formatErrorResponse(Throwable $throwable, string $requestId): array { // 模型未找到异常 @@ -61,10 +67,10 @@ class AetherExceptionHandler extends ExceptionHandler 'message' => $throwable->getMessage() ?: '请求的资源不存在', 'data' => env('APP_ENV') === 'dev' ? [ 'file' => $throwable->getFile(), - 'line' => $throwable->getLine() + 'line' => $throwable->getLine(), ] : null, 'request_id' => $requestId, - 'timestamp' => time() + 'timestamp' => time(), ]; } @@ -85,17 +91,20 @@ class AetherExceptionHandler extends ExceptionHandler 'data' => env('APP_ENV') === 'dev' ? [ 'file' => $throwable->getFile(), 'line' => $throwable->getLine(), - 'trace' => explode("\n", $throwable->getTraceAsString()) + 'trace' => explode("\n", $throwable->getTraceAsString()), ] : null, 'request_id' => $requestId, - 'timestamp' => time() + 'timestamp' => time(), ]; } private function formatValidationError(ValidationFailedException $e, string $requestId): array { $validatorInstance = new class extends AetherValidator { - protected function scenes(): array { return []; } + protected function scenes(): array + { + return []; + } }; return [ @@ -104,17 +113,20 @@ class AetherExceptionHandler extends ExceptionHandler 'data' => [ 'errors' => $validatorInstance->formatValidationErrors($e->validator), 'scene' => $e->getScene(), - 'validated_data' => env('APP_ENV') === 'dev' ? $e->validator->getData() : null + 'validated_data' => env('APP_ENV') === 'dev' ? $e->validator->getData() : null, ], 'request_id' => $requestId, - 'timestamp' => time() + 'timestamp' => time(), ]; } private function formatNativeValidationError(ValidationException $e, string $requestId): array { $validatorInstance = new class extends AetherValidator { - protected function scenes(): array { return []; } + protected function scenes(): array + { + return []; + } }; return [ @@ -122,15 +134,10 @@ class AetherExceptionHandler extends ExceptionHandler 'message' => '参数验证失败', 'data' => [ 'errors' => $validatorInstance->formatValidationErrors($e->validator), - 'validated_data' => env('APP_ENV') === 'dev' ? $e->validator->getData() : null + 'validated_data' => env('APP_ENV') === 'dev' ? $e->validator->getData() : null, ], 'request_id' => $requestId, - 'timestamp' => time() + 'timestamp' => time(), ]; } - - public function isValid(Throwable $throwable): bool - { - return true; - } -} \ No newline at end of file +} diff --git a/extend/Aether/PHP/Hyperf/Exception/AppExceptionHandler.php b/extend/Aether/PHP/Hyperf/Exception/AppExceptionHandler.php index 3a6603c..7dfd136 100644 --- a/extend/Aether/PHP/Hyperf/Exception/AppExceptionHandler.php +++ b/extend/Aether/PHP/Hyperf/Exception/AppExceptionHandler.php @@ -5,13 +5,14 @@ declare(strict_types=1); namespace Aether\Exception; use Aether\AetherValidator; +use Hyperf\Context\Context; use Hyperf\Contract\StdoutLoggerInterface; use Hyperf\ExceptionHandler\ExceptionHandler; use Hyperf\HttpMessage\Stream\SwooleStream; use Hyperf\Validation\ValidationException; use Psr\Http\Message\ResponseInterface; use Throwable; -use Hyperf\Context\Context; + use function Hyperf\Support\env; class AppExceptionHandler extends ExceptionHandler @@ -39,8 +40,13 @@ class AppExceptionHandler extends ExceptionHandler ->withBody(new SwooleStream(json_encode($result, JSON_UNESCAPED_UNICODE))); } + public function isValid(Throwable $throwable): bool + { + return true; + } + /** - * 统一错误响应格式 + * 统一错误响应格式. */ private function formatErrorResponse(Throwable $throwable, string $requestId): array { @@ -61,21 +67,24 @@ class AppExceptionHandler extends ExceptionHandler 'data' => env('APP_ENV') === 'dev' ? [ 'file' => $throwable->getFile(), 'line' => $throwable->getLine(), - 'trace' => explode("\n", $throwable->getTraceAsString()) + 'trace' => explode("\n", $throwable->getTraceAsString()), ] : null, 'request_id' => $requestId, - 'timestamp' => time() + 'timestamp' => time(), ]; } /** - * 格式化自定义验证异常 + * 格式化自定义验证异常. */ private function formatValidationError(ValidationFailedException $e, string $requestId): array { // 复用AetherValidator的错误格式化方法 $validatorInstance = new class extends AetherValidator { - protected function scenes(): array { return []; } + protected function scenes(): array + { + return []; + } }; return [ @@ -84,20 +93,23 @@ class AppExceptionHandler extends ExceptionHandler 'data' => [ 'errors' => $validatorInstance->formatValidationErrors($e->validator), 'scene' => $e->getScene(), // 直接从异常获取场景 - 'validated_data' => env('APP_ENV') === 'dev' ? $e->validator->getData() : null + 'validated_data' => env('APP_ENV') === 'dev' ? $e->validator->getData() : null, ], 'request_id' => $requestId, - 'timestamp' => time() + 'timestamp' => time(), ]; } /** - * 格式化原生验证异常(保持格式一致) + * 格式化原生验证异常(保持格式一致). */ private function formatNativeValidationError(ValidationException $e, string $requestId): array { $validatorInstance = new class extends AetherValidator { - protected function scenes(): array { return []; } + protected function scenes(): array + { + return []; + } }; return [ @@ -105,15 +117,10 @@ class AppExceptionHandler extends ExceptionHandler 'message' => '参数验证失败', 'data' => [ 'errors' => $validatorInstance->formatValidationErrors($e->validator), - 'validated_data' => env('APP_ENV') === 'dev' ? $e->validator->getData() : null + 'validated_data' => env('APP_ENV') === 'dev' ? $e->validator->getData() : null, ], 'request_id' => $requestId, - 'timestamp' => time() + 'timestamp' => time(), ]; } - - public function isValid(Throwable $throwable): bool - { - return true; - } -} \ No newline at end of file +} diff --git a/extend/Aether/PHP/Hyperf/Exception/BusinessException.php b/extend/Aether/PHP/Hyperf/Exception/BusinessException.php index 718478b..195e645 100644 --- a/extend/Aether/PHP/Hyperf/Exception/BusinessException.php +++ b/extend/Aether/PHP/Hyperf/Exception/BusinessException.php @@ -5,25 +5,30 @@ declare(strict_types=1); namespace Aether\Exception; use Hyperf\Server\Exception\ServerException; +use Throwable; class BusinessException extends ServerException { // 错误码常量(按业务模块划分) public const VALIDATION_ERROR = 400; // 参数验证失败 + public const AUTH_ERROR = 401; // 认证失败 + public const PERMISSION_DENY = 403; // 权限不足 + public const RESOURCE_NOT_FOUND = 404; // 资源不存在 + public const SCENE_NOT_FOUND = 400; /** - * 额外错误数据(如验证详情) + * 额外错误数据(如验证详情). */ protected ?array $errorData = null; public function __construct( string $message, int $code = 500, - ?\Throwable $previous = null, + ?Throwable $previous = null, ?array $errorData = null ) { parent::__construct($message, $code, $previous); @@ -31,10 +36,10 @@ class BusinessException extends ServerException } /** - * 获取额外错误数据 + * 获取额外错误数据. */ public function getErrorData(): ?array { return $this->errorData; } -} \ No newline at end of file +} diff --git a/extend/Aether/PHP/Hyperf/Exception/ValidationFailedException.php b/extend/Aether/PHP/Hyperf/Exception/ValidationFailedException.php index 871467b..c752fba 100644 --- a/extend/Aether/PHP/Hyperf/Exception/ValidationFailedException.php +++ b/extend/Aether/PHP/Hyperf/Exception/ValidationFailedException.php @@ -1,5 +1,7 @@ scene; } -} \ No newline at end of file +} diff --git a/extend/Aether/PHP/Hyperf/RpcExceptionHandler.php b/extend/Aether/PHP/Hyperf/RpcExceptionHandler.php index 1cde0fa..783be37 100644 --- a/extend/Aether/PHP/Hyperf/RpcExceptionHandler.php +++ b/extend/Aether/PHP/Hyperf/RpcExceptionHandler.php @@ -5,13 +5,13 @@ declare(strict_types=1); namespace Aether; use Hyperf\Context\ApplicationContext; +use Hyperf\Context\Context; use Hyperf\ExceptionHandler\ExceptionHandler; use Hyperf\Rpc\Protocol; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; use Psr\Http\Message\ResponseInterface; use Throwable; -use Hyperf\Context\Context; class RpcExceptionHandler extends ExceptionHandler { @@ -29,7 +29,6 @@ class RpcExceptionHandler extends ExceptionHandler ]; $protocol = ApplicationContext::getContainer()->get(Protocol::class); - // $response->getBody()->write($protocol->pack($data)); $response->getBody()->write($protocol->pack($data)); return $response; @@ -39,4 +38,4 @@ class RpcExceptionHandler extends ExceptionHandler { return true; } -} \ No newline at end of file +} diff --git a/extend/Aether/PHP/Hyperf/Traits/AetherEnum.php b/extend/Aether/PHP/Hyperf/Traits/AetherEnum.php index ee05ee2..858b291 100644 --- a/extend/Aether/PHP/Hyperf/Traits/AetherEnum.php +++ b/extend/Aether/PHP/Hyperf/Traits/AetherEnum.php @@ -59,7 +59,7 @@ trait AetherEnum /** * 根据值获取枚举实例(严格模式). * @param int|string $value 枚举值 - * @return AetherEnum|NoticeStatsModel|NoticeStatusEnum 枚举实例 + * @return AetherEnum 枚举实例 */ public static function fromValue(int|string $value): self { @@ -95,7 +95,7 @@ trait AetherEnum /** * 根据描述获取枚举实例(精确匹配). * @param string $description 描述文本 - * @return null|AetherEnum|NoticeStatsModel|NoticeStatusEnum 匹配的枚举实例,无匹配时返回null + * @return null|AetherEnum 匹配的枚举实例,无匹配时返回null */ public static function fromDescription(string $description): ?self { diff --git a/extend/Aether/PHP/Hyperf/Traits/AetherSoftDelete.php b/extend/Aether/PHP/Hyperf/Traits/AetherSoftDelete.php index 6be824a..7628b29 100644 --- a/extend/Aether/PHP/Hyperf/Traits/AetherSoftDelete.php +++ b/extend/Aether/PHP/Hyperf/Traits/AetherSoftDelete.php @@ -1,24 +1,26 @@ hidden, true)) { + if (! in_array('deleted_at', $this->hidden, true)) { $this->hidden[] = 'deleted_at'; } } -} \ No newline at end of file +} diff --git a/extend/Aether/PHP/Hyperf/Traits/AetherTree.php b/extend/Aether/PHP/Hyperf/Traits/AetherTree.php index 86b4e96..0776572 100644 --- a/extend/Aether/PHP/Hyperf/Traits/AetherTree.php +++ b/extend/Aether/PHP/Hyperf/Traits/AetherTree.php @@ -1,5 +1,7 @@ treeSortDirection ?? 'asc'; - return $direction === 'desc' - ? $b[$sortField] <=> $a[$sortField] - : $a[$sortField] <=> $b[$sortField]; - }); - } - - /** - * 获取指定节点的所有子节点ID + * 获取指定节点的所有子节点ID. */ public function getChildIds(int $id): array { @@ -84,7 +64,57 @@ trait AetherTree } /** - * 递归收集子节点ID + * 获取节点的完整路径. + */ + public function getPath(int $id): array + { + $parentField = $this->getParentIdField(); + // 安全调用newQuery() + $node = $this->newQuery()->find($id); + if (! $node) { + return []; + } + + $path = [$node->toArray()]; + $parentId = $node[$parentField]; + + while ($parentId > 0) { + $parent = $this->newQuery()->find($parentId); + if (! $parent) { + break; + } + array_unshift($path, $parent->toArray()); + $parentId = $parent[$parentField]; + } + + return $path; + } + + /** + * 抽象方法:获取父ID字段名(由子类实现). + */ + abstract protected function getParentIdField(): string; + + /** + * 抽象方法:获取排序字段名(由子类实现). + */ + abstract protected function getSortField(): string; + + /** + * 树形节点排序. + */ + protected function sortTreeItems(array &$items, string $sortField): void + { + usort($items, function ($a, $b) use ($sortField) { + $direction = $this->treeSortDirection ?? 'asc'; + return $direction === 'desc' + ? $b[$sortField] <=> $a[$sortField] + : $a[$sortField] <=> $b[$sortField]; + }); + } + + /** + * 递归收集子节点ID. */ private function collectChildIds(array $items, int $parentId, string $parentField, array &$ids): void { @@ -95,31 +125,4 @@ trait AetherTree } } } - - /** - * 获取节点的完整路径 - */ - public function getPath(int $id): array - { - $parentField = $this->getParentIdField(); - // 安全调用newQuery() - $node = $this->newQuery()->find($id); - if (!$node) { - return []; - } - - $path = [$node->toArray()]; - $parentId = $node[$parentField]; - - while ($parentId > 0) { - $parent = $this->newQuery()->find($parentId); - if (!$parent) { - break; - } - array_unshift($path, $parent->toArray()); - $parentId = $parent[$parentField]; - } - - return $path; - } }