我能够使用可重复使用的PaypalController
方法实现postPayment()
,该方法接受商品及其价格,并创建Paypal付款,并重定向到Paypal付款页。
class PaypalController extends Controller {
private static $_api_context;
private static function initialize() {
//initialize api context
}
public static function postPayment($items, $currency, $description) {
self::initialize();
//create item list, transaction, payment objects, etc
$payment->create(PaypalController::$_api_context);
...
return redirect()->away($redirect_url); // redirect to paypal
}
}
PaypalController
由其他控制器静态调用。例如,AuthController
可能会在用户注册到我的网站后立即调用它来请求用户付款:
class AuthController extends Controller {
public function postRegister(Request $request) {
return PaypalController::postPayment($items, 'JPY', 'description');
}
}
基本上,PaypalController
会将Redirect
返回给AuthController
,并返回它,以执行重定向到Paypal付款页面。
我想知道这是不是一个好的设计 - 控制器调用不同的控制器,是吗?
如果没有,那么更好的方法是什么?也许将我的代码从PaypalController转移到自定义服务提供程序,或自定义助手,或其他什么?我对Laravel很新,我很感激一些指导。
答案 0 :(得分:2)
不,这不是一个好习惯。您应该将业务逻辑抽象为服务/存储库类。例如:
创建一个接口作为合同:
namespace App\Services\Paypal;
interface PaypalInterface {
public function PostRegister(Array $array, /*More $params if necessary*/);
}
然后实施合同:
namespace App\Services\Paypal;
class PaypalService implements PaypalInterface {
// Must match the method signature declared in the interface
public function PostRegister(Array $array, /*$More $params if necessary*/) {
// Do the process here
}
}
然后使用contract / interface作为依赖项。因此,在您的PaypalController
或任何其他控制器中,您可以(重新)使用它,如:
namespace App\Http\Controllers;
use App\Http\Request;
use App\Services\Paypal\PaypalInterface;
class AuthController extends Controller {
public function postPayment(Request $request, PaypalInterface $paypalService) {
return $paypalService->postRegister($request->all());
}
}
在这种情况下,服务提供商中的register the binding(实现接口)(基本上在AppServiceProvider
中)。这是基本的工作流程。为什么是接口,因为控制器(客户端/消费者类)应该与Contract / Interface通信而不是具体的实现。
This article of mine may help you但请记住,这不是100%解耦,它仍然与Laravel
框架相结合,您甚至可以将服务解耦。
注意:这是一种最佳实践,但不要盲目地对每个项目/问题采用这种方法,只要明智地选择应该这样做,它实际上取决于上下文,但不要只为它而死。目前的情况可以遵循这一点。
答案 1 :(得分:1)
你的postPayment
是一种静态方法这一事实对我而言是一种代码味道,它告诉了#34; Nope,而不是在控制器内#34;
正如您所说,我认为服务会是一个更好的地方,如果您愿意,可以查看Omnipay。
您也可以将PaypalController
抽象化,AuthController
将扩展此项(仅当您必须在多个控制器中使用postPayment
时)。
您可以执行PaypalTrait
并在AuthController
内使用它(仅当您必须在多个控制器中使用postPayment
时)。
当然,如果对您有意义,您可以将第一个解决方案与其他解决方案结合起来。
这个问题有很多答案,我不认为存在完美的答案,这实际上取决于你的建设和需要。
答案 2 :(得分:1)
这不是正确的方法。 Rember,控制器应该只接受请求并将其发送到正确的服务,而不是自己处理商务逻辑。
此规则适用:当您需要从另一个控制器调用控制器方法时,它会闻到错误的代码
相反,使用服务提供者和服务类来处理您的paypal逻辑。服务类将处理paypal逻辑,稍后当您在控制器中需要它时将使用它:
//SERVICE CLASS
class PayPalService
{
public function processPayment(){ //... }
}
服务提供商用于在应用程序中注册服务类:您告诉Laravel当您需要PayPalService
它应该构建并为您返回时
//SERVICE PROVIDER: binds the creation of the service in the ioc container
class PayPalServiceProvider extends ServiceProvider
{
public function register()
{
//use singleton or bind to bind the service in the ioc container
$this->app->singleton( PayPalService::class, function()
{
return new PayPalService();
});
}
}
然后,当您需要PayPalService
课程时,您应该让Laravel在您的控制器中自动注入服务:
class AuthController extends Controller
{
public function postRegister(Request $request, PayPalService $paypal) {
return $paypal->processPayment();
}
}
如果需要,可以使用服务类的接口
进一步改进此设计