Laravel:控制器或中间件
Laravel: Controller or Middleware
我正在使用 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);
来实例化正确的实现。核心概念还是在这个上下文中,你需要哪个provider。对此有很多选择,服务,工厂等。但是做一个容器提供者版本,当你在 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();
}
我正在使用 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);
来实例化正确的实现。核心概念还是在这个上下文中,你需要哪个provider。对此有很多选择,服务,工厂等。但是做一个容器提供者版本,当你在 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();
}