laravel - Laravel:控制器或中间件
问题描述
我正在使用 Laravel 6.9.0。这是我的付款控制器:
class PaymentController extends Controller
{
public function __construct(){
$this->middleware('payment.test');
$this->middleware('payment.check');
}
public function pay(){
$this->payment->pay();
}
public function refund(){
$this->payment->refund();
}
public function checkOrder(){
$this->payment->checkOrder();
}
}
payment.test
中间件做了这些:
- 写请求日志
- 检查商家是否存在
- 解密请求
payment.check
中间件用于检查它是哪种付款方式,例如 applepay 或 googlelpay 。
但是从官方文档来看,中间件是用来过滤 HTTP 请求的,验证你的应用程序的用户是否经过身份验证。
好像payment.check
不属于这个。因此,我将payment.check
中间件更改为控制器。因为所有的方法都要检查支付,所以我把它放在了构造函数中。但是,我必须在检查之前解密请求,所以我的构造函数现在是
$this->middleware('payment.test');
$this->middleware(function ($request, $next) {
$this->checkPayment($request);
return $next($request);
});
checkPayment
看起来像这样:
private function checkPayment($request){
if($request->aaa == 'aaa'){
switch($request->type){
case '001':
$type = 'apple';
break;
case '111':
$type = 'google';
break;
...
}
}else{
switch($request->code){
case 'android':
$type = 'android';
break;
...
}
}
$this->payment = app($type);
}
它使我的控制器丑陋。我觉得将它写入中间件看起来更加模块化和清晰。将它写入控制器真的比中间件更好吗?或者有什么其他建议?
解决方案
正如我所看到的那样,您的整个问题是,即使您的逻辑最终通过调用来实例化正确的实现也是如此$this->payment = app($type);
。核心概念还是在这个上下文中,你需要哪个提供者。这有很多选项,服务,工厂等,但是做一个容器提供者版本,当你在Laravel
.
想象一下拥有你的PaymentProviderInterface
,我会绑定它来解决使用哪个支付提供商。将它与您在任何情况下都可以解析请求对象相结合,您可以将所有这些移动到提供者,我会创建一个新的。PaymentProvider
并将其注册为任何其他提供者。
class PaymentsProvider {
public const APPLE_PAYMENT_PROVIDER = 'apple';
public const GOOGLE_PAYMENT_PROVIDER = 'google';
public const ANDROID_PAYMENT_PROVIDER = 'android';
public function boot() {
$this->app->bind(PaymentProviderInterface::class, function () {
/** @var Request $request **/
$request = resolve(Request::class);
$type = null;
if($request->aaa == 'aaa') {
$type = $this->resolvePaymentByType($request->type);
} else {
$type = $this->resolvePaymentByCode($request->code);
}
return resolve($type);
});
}
private function resolvePaymentByType(string $type): string
{
if ($type === '001') {
return static::APPLE_PAYMENT_PROVIDER;
}
if ($type === '111') {
return static::GOOGLE_PAYMENT_PROVIDER;
}
throw new Exception('Invalid state');
}
private function resolvePaymentByCode(string $code): string
{
if ($type === static::ANDROID_PAYMENT_PROVIDER) {
return static::ANDROID_PAYMENT_PROVIDER;
}
throw new Exception('Invalid state');
}
}
一般来说,我不喜欢开关盒,如果你喜欢,你可以使用它们,我认为这更干净。另一个小的优化,而不是让魔术字符串使用常量,它更具可读性并且有很多好处。由于我们将所有内容绑定到PaymentProviderInterface
,因此通过像这样解析您的提供者,这将使您的控制器真正干净。为了避免您没有请求的情况,我会在每种方法中注入。
class PaymentController extends Controller
{
public function pay(PaymentProviderInterface $payment){
$payment->pay();
}
推荐阅读
- php - PHP CMD - 如何打印这个特殊字符(^&|<>)?
- javascript - 反应查询结果对象是否由于关闭而过时?
- javascript - 当组件在视图中时,在 react-spring 中启动动画
- python - 如何使用 python 将 .csv 文件上传到 Cassandra?
- r - 基于两列之间滞后的子集data.frame
- javascript - 如何绘制png图像的形状?
- excel - VBA 从数组动态构建公式
- javascript - 使用 jQuery 克隆、过滤和 plonk HTML 节点
- javascript - NestJS 中的 TypeORM - 如何在实体中获取 MySQL 嵌套对象并对子关系进行“位置”查询?
- git - 在 gihub 操作中解密 GPG 加密文件失败,似乎是由于文件损坏