feat : pay Adapter
Some checks are pending
Build Docker / build (push) Waiting to run

This commit is contained in:
2025-09-04 23:08:54 +08:00
parent 595d3d3276
commit f4b812f861
25 changed files with 694 additions and 1 deletions

87
README Normal file
View File

@@ -0,0 +1,87 @@
## 仓库
- [hhl_hyperf_service](https://codeup.aliyun.com/67039465d8d1ada68263f984/hhl/rewrite/hyperf_service.git) - git远程仓库地址
## 特性
- **最新技术栈**:使用 PHP8.3/hyperf3.1/swoole5.1.4 等后端前沿技术开发
## 文档
[文档地址 Github](https://hyperf.wiki/3.1/)
## 前序准备
- [php8.3](https://www.php.net/) 和 [git](https://git-scm.com/) - 项目开发环境
- [swoole](https://www.swoole.com/) - 熟悉 swoole 特性
- [php8.3](https://www.php.net/) - 熟悉 php 基础语法
- [hyperf](https://hyperf.wiki/3.1/) - 熟悉 `hyperf` 基本语法
## 安装和使用
- 安装 swoole 和 xlswriter 扩展
```
自行搜索安装教程
```
- 获取代码
```bash
git clone https://git.ctexthuang.com/ctexthuang/hyperf_test.git
mkdir uploads
```
- vendor
```bash
composer install
```
- 运行
```bash
cp .env.example .env
vim .env
php bin/hyperf.php start
```
- command 函数
```bash
#框架自有
php bin/hyperf.php gen:controller LoginController
php bin/hyperf.php gen:model UserModel
php bin/hyperf.php gen:request LoginRequest
php bin/hyperf.php gen:command TestCommand
php bin/hyperf.php gen:job TestJob
php bin/hyperf.php gen:listener TestListener
php bin/hyperf.php gen:middleware AuthMiddleware
php bin/hyperf.php gen:amqp-consumer DemoConsumer
php bin/hyperf.php gen:amqp-producer DemoProducer
#新增命令
php bin/hyperf.php gen:service LoginService
php bin/hyperf.php gen:cron OssTask
php bin/hyperf.php gen:event TestEvent
```
## Git 贡献提交规范
- `feat` 新功能
- `fix` 修补 bug
- `docs` 文档
- `style` 格式、样式(不影响代码运行的变动)
- `refactor` 重构(即不是新增功能,也不是修改 BUG 的代码)
- `perf` 优化相关,比如提升性能、体验
- `test` 添加测试
- `build` 编译相关的修改,对项目构建或者依赖的改动
- `ci` 持续集成修改
- `chore` 构建过程或辅助工具的变动
- `revert` 回滚到上一个版本
- `workflow` 工作流改进
- `mod` 不确定分类的修改
- `wip` 开发中
- `types` 类型

View File

@@ -0,0 +1,77 @@
<?php
namespace App\Aspect;
use App\Lib\Return\AdminReturn;
use App\Lib\Return\CommonReturn;
use App\Lib\Return\TestReturn;
use Hyperf\Context\Context;
use Hyperf\Di\Annotation\Aspect;
use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\Di\Aop\ProceedingJoinPoint;
use Hyperf\Di\Exception\Exception;
use Hyperf\HttpServer\Contract\RequestInterface;
#[Aspect]
class CommonReturnAspect extends AbstractAspect
{
/**
* 需要切入的类
* @var array|string[]
*/
public array $classes = [
AdminReturn::class,
TestReturn::class,
// CommonReturn::class,
];
/**
* 需要切入的注解
* @var array
*/
public array $annotations = [];
/**
* 依赖注入容器
* @param RequestInterface $request
* @param int $userId
*/
public function __construct(
private readonly RequestInterface $request,
private int $userId = 0
) {}
/**
* 切面逻辑
* @param ProceedingJoinPoint $proceedingJoinPoint
* @return mixed
* @throws Exception
*/
public function process(ProceedingJoinPoint $proceedingJoinPoint): mixed
{
echo 1;
var_dump(1);
// 在调用前进行处理
$result = $proceedingJoinPoint->process();
// 在调用后进行处理
// 未登录返回 0
$this->userId = Context::get('user_id',0);
$this->writeResponseLog(json_encode($result));
return $result;
}
/**
* 写入请求日志
* @param string $content
* @return void
*/
private function writeResponseLog(string $content): void
{
echo json_encode($this->request->all());
echo $this->userId;
echo json_encode($content);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace App\Command;
use Hyperf\Command\Annotation\Command;
use Hyperf\Devtool\Generator\GeneratorCommand;
use Psr\Container\ContainerInterface;
#[Command]
class ServiceCommand extends GeneratorCommand
{
/**
* 构造函数 生成指令
* @param ContainerInterface $container
*/
public function __construct(protected ContainerInterface $container)
{
parent::__construct('gen:service');
}
/**
* 获取 stub 文件
* @return string
*/
protected function getStub(): string
{
return __DIR__ . '/stubs/service.stub';
}
/**
* 获取默认命名空间
* @return string
*/
protected function getDefaultNamespace(): string
{
return 'App\\Service';
}
/**
* 生成逻辑
* @return void
*/
public function configure(): void
{
$this->setDescription('Create a new service class');
parent::configure();
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
* @web_site https://ctexthuang.com
*/
declare(strict_types=1);
namespace %NAMESPACE%;
class %CLASS% extends
{
public function handle()
{
//todo Write logic
}
}

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace App\Constants;
use Hyperf\Constants\Annotation\Constants;
use Hyperf\Constants\Annotation\Message;
use Hyperf\Constants\EnumConstantsTrait;
#[Constants]
enum ReturnCode: int
{
use EnumConstantsTrait;
#[Message("Server Error!")]
case SERVER_ERROR = 500;
/**
* 返回成功
*/
#[Message('return success')]
case SUCCESS = 0;
/**
* 返回失败
*/
#[Message('return fail')]
case ERROR = 1;
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace App\Controller\Test;
use App\Service\Test\Adapter\PayService;
use App\Service\Test\AdapterTestService;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;
#[Controller(prefix: 'adapter/test')]
class AdapterTestController
{
#[RequestMapping(path: 'pay', methods: 'GET')]
public function pay()
{
return (new PayService)->handle();
}
public function cache()
{
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Interface\Test\Adapter;
interface PaymentGateway
{
public function pay(float $amount): array;
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Lib\Return;
class AdminReturn extends CommonReturn
{
/**
* @param array $res
* @return array
*/
protected function afterSuccess(array $res): array
{
return $res;
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace App\Lib\Return;
use App\Constants\ReturnCode;
abstract class CommonReturn
{
/**
* 通用 success 返回
* @param string $msg
* @param array $data
* @param ReturnCode $code
* @param array $debug
* @return array
*/
final public function success(string $msg = 'success', array $data = [], ReturnCode $code = ReturnCode::SUCCESS, array $debug = []): array
{
$res = [
'code' => $code,
'message' => $msg,
'data' => $data
];
return $this->afterSuccess(array_merge($res, $debug));
}
/**
* 通用 fail 返回
* @param string $msg
* @param array $data
* @param ReturnCode $code
* @param array $debug
* @return array
*/
final public function error(string $msg = 'error', ReturnCode $code = ReturnCode::ERROR, array $data = [], array $debug = []): array
{
$res = [
'code' => $code,
'message' => $msg,
'data' => $data
];
return $this->afterSuccess(array_merge($res, $debug));
}
/**
* 通用类调子类返回方便切面类识别
* @param array $res
* @return array
*/
abstract protected function afterSuccess(array $res): array;
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Lib\Return;
class TestReturn extends CommonReturn
{
/**
* @param array $res
* @return array
*/
protected function afterSuccess(array $res): array
{
return $res;
}
}

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace App\Middleware;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
class CoreMiddleware implements MiddlewareInterface
{
public function __construct(protected ContainerInterface $container)
{
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
return $handler->handle($request);
}
}

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace App\Middleware;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
class CorsMiddleware implements MiddlewareInterface
{
public function __construct(protected ContainerInterface $container)
{
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
return $handler->handle($request);
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
* @web_site https://ctexthuang.com
*/
declare(strict_types=1);
namespace App\Service;
abstract class BaseService
{
/**
* 主体函数抽象类
*/
abstract public function handle();
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
* @web_site https://ctexthuang.com
*/
declare(strict_types=1);
namespace App\Service\Test\Adapter;
use App\Service\Test\TestBaseService;
class CacheService extends TestBaseService
{
public function handle()
{
//todo Write logic
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
* @web_site https://ctexthuang.com
*/
declare(strict_types=1);
namespace App\Service\Test\Adapter\Pay;
use App\Interface\Test\Adapter\PaymentGateway;
class AlipayAdapter implements PaymentGateway
{
/**
* @var AlipayService
*/
private AlipayService $alipay;
public function __construct(AlipayService $alipay)
{
$this->alipay = $alipay;
}
/**
* @param float $amount
* @return array
*/
public function pay(float $amount): array
{
return $this->alipay->sendPayment($amount);
}
}

View File

@@ -0,0 +1,27 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
* @web_site https://ctexthuang.com
*/
declare(strict_types=1);
namespace App\Service\Test\Adapter\Pay;
class AlipayService
{
/**
* @param float $amount
* @return array
*/
public function sendPayment(float $amount): array
{
return [
'code' => 'success',
'amount' => $amount,
];
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
* @web_site https://ctexthuang.com
*/
declare(strict_types=1);
namespace App\Service\Test\Adapter\Pay;
use App\Interface\Test\Adapter\PaymentGateway;
class WechatPayAdapter implements PaymentGateway
{
/**
* @var WechatPayService
*/
private WechatPayService $wechatPay;
public function __construct(WechatPayService $wechatPay)
{
$this->wechatPay = $wechatPay;
}
/**
* @param float $amount
* @return array
*/
public function pay(float $amount): array
{
return $this->wechatPay->makePayment($amount);
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
* @web_site https://ctexthuang.com
*/
declare(strict_types=1);
namespace App\Service\Test\Adapter\Pay;
class WechatPayService
{
/**
* @param float $amount
* @return array
*/
public function makePayment(float $amount): array
{
return [
'code' => 'error',
'status' => 'fail',
'amount' => $amount,
];
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
* @web_site https://ctexthuang.com
*/
declare(strict_types=1);
namespace App\Service\Test\Adapter;
use App\Service\Test\Adapter\Pay\AlipayAdapter;
use App\Service\Test\Adapter\Pay\AlipayService;
use App\Service\Test\Adapter\Pay\WechatPayAdapter;
use App\Service\Test\Adapter\Pay\WechatPayService;
use App\Service\Test\TestBaseService;
class PayService extends TestBaseService
{
public function handle()
{
$alipayRes = (new AlipayAdapter(new AlipayService))->pay(100.00);
echo 'alipayRes:'. json_encode($alipayRes).PHP_EOL;
$wechatPay = new WechatPayService();
$wechatPayAdapter = new WechatPayAdapter($wechatPay);
$wechatPayRes = $wechatPayAdapter->pay(100.00);
echo 'wechatPayRes:'. json_encode($wechatPayRes).PHP_EOL;
return $this->return->success('success',[
'alipayRes' => $alipayRes,
'wechatPayRes' => $wechatPayRes,
]);
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* This service file is part of item.
*
* @author ctexthuang
* @contact ctexthuang@qq.com
* @web_site https://ctexthuang.com
*/
declare(strict_types=1);
namespace App\Service\Test;
use App\Service\BaseService;
class AdapterTestService extends TestBaseService
{
public function handle(): array
{
return $this->return->success();
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Service\Test;
use App\Lib\Return\TestReturn;
use App\Service\BaseService;
use Hyperf\Di\Annotation\Inject;
abstract class TestBaseService extends BaseService
{
/**
* @var TestReturn
*/
#[Inject]
protected TestReturn $return;
abstract public function handle();
}

View File

@@ -22,7 +22,7 @@ return [
'log_level' => [
LogLevel::ALERT,
LogLevel::CRITICAL,
LogLevel::DEBUG,
// LogLevel::DEBUG,
LogLevel::EMERGENCY,
LogLevel::ERROR,
LogLevel::INFO,

View File

@@ -0,0 +1,11 @@
{
"dev": {
"host": "https://test.ctexthuang.com"
},
"local": {
"host": "http://127.0.0.1:9501"
},
"prod": {
"host": "https://prod.ctexthuang.com"
}
}

9
request/test.http Normal file
View File

@@ -0,0 +1,9 @@
### Adapte pay test
GET {{host}}/adapter/test/pay
Content-Type: application/x-www-form-urlencoded
account=13632877014&password=123456
> {%
client.global.set("admin_token", response.body.data.token);
%}