更新统一使用 PHPDoc + PSR-19 标准注释

This commit is contained in:
技术老胡
2026-04-21 08:38:59 +08:00
parent dcd58e24ce
commit 9a16a88640
252 changed files with 9218 additions and 659 deletions

View File

@@ -8,14 +8,18 @@ use app\model\merchant\MerchantApiCredential;
use app\repository\merchant\credential\MerchantApiCredentialRepository;
/**
* 商户接口凭证查询服务。
* 商户 API 凭证查询服务。
*
* 负责凭证列表和详情展示,不承载验签和写入逻辑。
*
* @property MerchantApiCredentialRepository $merchantApiCredentialRepository 商户 API 凭证仓库
*/
class MerchantApiCredentialQueryService extends BaseService
{
/**
* 构造函数,注入对应依赖
* 构造方法
*
* @param MerchantApiCredentialRepository $merchantApiCredentialRepository 商户 API 凭证仓库
*/
public function __construct(
protected MerchantApiCredentialRepository $merchantApiCredentialRepository
@@ -23,7 +27,12 @@ class MerchantApiCredentialQueryService extends BaseService
}
/**
* 分页查询商户接口凭证。
* 分页查询商户 API 凭证。
*
* @param array $filters 筛选条件
* @param int $page 页码
* @param int $pageSize 每页条数
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 分页对象
*/
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10)
{
@@ -63,7 +72,10 @@ class MerchantApiCredentialQueryService extends BaseService
}
/**
* 查询商户接口凭证详情。
* 查询商户 API 凭证详情。
*
* @param int $id 商户 API 凭证ID
* @return MerchantApiCredential|null 凭证模型
*/
public function findById(int $id): ?MerchantApiCredential
{
@@ -73,6 +85,9 @@ class MerchantApiCredentialQueryService extends BaseService
/**
* 查询商户对应的接口凭证详情。
*
* @param int $merchantId 商户ID
* @return MerchantApiCredential|null 凭证模型
*/
public function findByMerchantId(int $merchantId): ?MerchantApiCredential
{
@@ -82,6 +97,9 @@ class MerchantApiCredentialQueryService extends BaseService
/**
* 统一构造查询对象。
*
* @param bool $maskCredentialValue 是否脱敏接口凭证
* @return \Illuminate\Database\Eloquent\Builder 查询构造器
*/
private function baseQuery(bool $maskCredentialValue = false)
{
@@ -112,6 +130,9 @@ class MerchantApiCredentialQueryService extends BaseService
/**
* 给详情行补充展示字段。
*
* @param object|null $row 原始记录对象
* @return MerchantApiCredential|null 凭证模型
*/
private function decorateRow(mixed $row): ?MerchantApiCredential
{

View File

@@ -15,12 +15,20 @@ use app\repository\merchant\base\MerchantRepository;
/**
* 商户对外接口凭证与签名校验服务。
*
* 负责外部支付接口签名验、接口凭证发放和最近使用时间更新。
* 负责商户外部接口签名验、接口凭证发放和最近使用时间更新。
*
* @property MerchantRepository $merchantRepository 商户仓库
* @property MerchantApiCredentialRepository $merchantApiCredentialRepository 商户 API 凭证仓库
* @property MerchantApiCredentialQueryService $merchantApiCredentialQueryService 商户 API 凭证查询服务
*/
class MerchantApiCredentialService extends BaseService
{
/**
* 构造函数,注入对应依赖
* 构造方法
*
* @param MerchantRepository $merchantRepository 商户仓库
* @param MerchantApiCredentialRepository $merchantApiCredentialRepository 商户 API 凭证仓库
* @param MerchantApiCredentialQueryService $merchantApiCredentialQueryService 商户 API 凭证查询服务
*/
public function __construct(
protected MerchantRepository $merchantRepository,
@@ -30,7 +38,12 @@ class MerchantApiCredentialService extends BaseService
}
/**
* 分页查询商户接口凭证。
* 分页查询商户 API 凭证。
*
* @param array $filters 筛选条件
* @param int $page 页码
* @param int $pageSize 每页条数
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 分页对象
*/
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10)
{
@@ -40,7 +53,12 @@ class MerchantApiCredentialService extends BaseService
/**
* 校验外部支付接口的 MD5 签名。
*
* @return array{merchant:\app\model\merchant\Merchant,credential:\app\model\merchant\MerchantApiCredential}
* 会先校验商户和接口凭证是否存在,再按签名规则计算并比对请求签名。
*
* @param array $payload 请求载荷
* @return array{merchant: Merchant, credential: MerchantApiCredential} 校验通过后的商户和凭证数据
* @throws ValidationException
* @throws ResourceNotFoundException
*/
public function verifyMd5Sign(array $payload): array
{
@@ -66,15 +84,17 @@ class MerchantApiCredentialService extends BaseService
/** @var MerchantApiCredential|null $credential */
$credential = $this->merchantApiCredentialRepository->findByMerchantId($merchantId);
if (!$credential || (int) $credential->status !== AuthConstant::LOGIN_STATUS_ENABLED) {
throw new ValidationException('商户接口凭证未开通');
throw new ValidationException('商户 API 凭证未开通');
}
if ($providedKey !== '' && !hash_equals((string) $credential->api_key, $providedKey)) {
throw new ValidationException('商户接口凭证错误');
throw new ValidationException('商户 API 凭证错误');
}
// 签名字段本身不参与原文拼接,只保留业务参数。
$params = $payload;
unset($params['sign'], $params['sign_type'], $params['key']);
// 过滤空值并按键名排序,保证不同参数顺序下得到同一签名串。
foreach ($params as $paramKey => $paramValue) {
if ($paramValue === '' || $paramValue === null) {
unset($params[$paramKey]);
@@ -84,12 +104,14 @@ class MerchantApiCredentialService extends BaseService
$key = (string) $credential->api_key;
$query = [];
// 旧版 ePay 采用 `a=1&b=2` 再拼接 key 的方式验签,这里保持兼容。
foreach ($params as $paramKey => $paramValue) {
$query[] = $paramKey . '=' . $paramValue;
}
$base = implode('&', $query) . $key;
$expected = md5($base);
// 使用常量时间比较,避免签名对比被时序差异放大。
if (!hash_equals(strtolower($expected), strtolower($sign))) {
throw new ValidationException('签名验证失败');
}
@@ -107,6 +129,10 @@ class MerchantApiCredentialService extends BaseService
* 为商户生成并保存一份新的接口凭证。
*
* 返回值是明文接口凭证值,只会在调用时完整出现一次,后续仅保存脱敏展示。
*
* @param int $merchantId 商户ID
* @return string 新接口凭证
* @throws ResourceNotFoundException
*/
public function issueCredential(int $merchantId): string
{
@@ -130,7 +156,10 @@ class MerchantApiCredentialService extends BaseService
}
/**
* 查询商户接口凭证详情。
* 查询商户 API 凭证详情。
*
* @param int $id 商户 API 凭证ID
* @return MerchantApiCredential|null 凭证模型
*/
public function findById(int $id): ?MerchantApiCredential
{
@@ -139,6 +168,9 @@ class MerchantApiCredentialService extends BaseService
/**
* 查询商户对应的接口凭证详情。
*
* @param int $merchantId 商户ID
* @return MerchantApiCredential|null 凭证模型
*/
public function findByMerchantId(int $merchantId): ?MerchantApiCredential
{
@@ -146,7 +178,13 @@ class MerchantApiCredentialService extends BaseService
}
/**
* 新增或更新商户接口凭证。
* 新增或更新商户 API 凭证。
*
* 如果商户已有凭证,则转为更新;否则创建新记录。
*
* @param array $data 凭证数据
* @return MerchantApiCredential 凭证模型
* @throws ResourceNotFoundException
*/
public function create(array $data): MerchantApiCredential
{
@@ -158,6 +196,7 @@ class MerchantApiCredentialService extends BaseService
$current = $this->merchantApiCredentialRepository->findByMerchantId($merchantId);
if ($current) {
// 同一商户只保留一份凭证,已有记录时优先走更新,避免重复创建。
$updated = $this->update((int) $current->id, $data);
if ($updated) {
return $updated;
@@ -168,7 +207,11 @@ class MerchantApiCredentialService extends BaseService
}
/**
* 修改商户接口凭证。
* 修改商户 API 凭证。
*
* @param int $id 商户 API 凭证ID
* @param array $data 凭证数据
* @return MerchantApiCredential|null 凭证模型
*/
public function update(int $id, array $data): ?MerchantApiCredential
{
@@ -186,7 +229,10 @@ class MerchantApiCredentialService extends BaseService
}
/**
* 删除商户接口凭证。
* 删除商户 API 凭证。
*
* @param int $id 商户 API 凭证ID
* @return bool 是否删除成功
*/
public function delete(int $id): bool
{
@@ -196,9 +242,13 @@ class MerchantApiCredentialService extends BaseService
/**
* 使用商户 ID 和接口凭证直接进行身份校验。
*
* 该方法用于兼容 epay 风格的查询接口,不涉及签名串验签。
* 该方法用于兼容 ePay 风格的查询接口,不涉及签名串验签。
*
* @return array{merchant:\app\model\merchant\Merchant,credential:\app\model\merchant\MerchantApiCredential}
* @param int $merchantId 商户ID
* @param string $key 接口凭证
* @return array{merchant: Merchant, credential: MerchantApiCredential} 商户和凭证数据
* @throws ValidationException
* @throws ResourceNotFoundException
*/
public function authenticateByKey(int $merchantId, string $key): array
{
@@ -215,11 +265,12 @@ class MerchantApiCredentialService extends BaseService
/** @var MerchantApiCredential|null $credential */
$credential = $this->merchantApiCredentialRepository->findByMerchantId($merchantId);
if (!$credential || (int) $credential->status !== AuthConstant::LOGIN_STATUS_ENABLED) {
throw new ValidationException('商户接口凭证未开通');
throw new ValidationException('商户 API 凭证未开通');
}
// 同样使用常量时间比较,避免明文 key 对比暴露额外信息。
if (!hash_equals((string) $credential->api_key, $key)) {
throw new ValidationException('商户接口凭证错误');
throw new ValidationException('商户 API 凭证错误');
}
$credential->last_used_at = $this->now();
@@ -233,9 +284,15 @@ class MerchantApiCredentialService extends BaseService
/**
* 整理写入字段。
*
* @param array $data 凭证数据
* @param bool $isUpdate 是否更新
* @param MerchantApiCredential|null $current 当前凭证
* @return array{merchant_id: int, sign_type: int, status: int, api_key?: string} 标准化后的写入数据
*/
private function normalizePayload(array $data, bool $isUpdate, ?MerchantApiCredential $current = null): array
{
// 更新场景下以现有记录的 merchant_id 为准,避免把凭证误挂到别的商户。
$merchantId = (int) ($current?->merchant_id ?? ($data['merchant_id'] ?? 0));
$payload = [
'merchant_id' => $merchantId,
@@ -247,6 +304,7 @@ class MerchantApiCredentialService extends BaseService
if ($apiKey !== '') {
$payload['api_key'] = $apiKey;
} elseif (!$isUpdate) {
// 新增凭证时如果前端没有传入明文 key就自动补一份随机值。
$payload['api_key'] = $this->generateCredentialValue();
}
@@ -255,6 +313,8 @@ class MerchantApiCredentialService extends BaseService
/**
* 生成新的接口凭证值。
*
* @return string 接口凭证
*/
private function generateCredentialValue(): string
{
@@ -263,3 +323,8 @@ class MerchantApiCredentialService extends BaseService
}