2016-02-26 74 views
3

我能够使用可重复使用的postPayment()方法实施PaypalController,该方法接受商品及其价格,创建Paypal付款并重定向到Paypal付款页面。从另一个控制器调用Controller是Laravel的一个良好实践吗?

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返回RedirectAuthController,这也返回它,执行重定向到Paypal付款页面。

我想知道这是不是一个好的设计 - 一个控制器调用不同的控制器,是吗?

如果不是,那么更好的方法是什么?也许将我的代码从PaypalController移动到自定义服务提供程序,或者自定义助手或其他东西?我对Laravel很新,我希望能有一些指导。

回答

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 
    } 
} 

然后使用合同/接口的依赖。所以,在你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)(接口来实现)。这是基本的工作流程。为什么一个接口,因为,控制器(客户端/消费者类)应该谈论合同/接口,而不是一个具体的实施。

This article of mine may help you但请记住,这不是100%解耦,它仍然与Laravel框架耦合在一起,您甚至可以解耦服务。


注:这是一个最好的做法,但不盲从这种方法对每个项目/问题,只是明智地选择了当你应该这样做,这真的取决于上下文,但不只是死它。当前的情况很好,遵循这一点。

+0

我为什么要使用界面?如果我在这种特殊情况下使用接口,恐怕我可能会过度工程。 – Obay

+0

这是解耦业务逻辑的正确/最佳实践,也就是说:编程到接口,而不是具体实现。换句话说,对抽象类型(接口)的依赖使得双方不会紧密地解耦,并且即使在不改变应用程序逻辑的情况下也可以调用依赖关系。但就像我说的那样,做你认为对自己更好的事情,不要遵循任何规则,直到你意识到需要,直到你理解为止。无论如何,它带来了话题。 –

+0

此外,[检查此](https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=program%20to%20an%20interface%20not%20an%20实施) 。 –

1

事实上,你的postPayment是一个静态方法是一种代码味道,告诉我“不要,不在控制器内”。

  • 正如你所说,我认为服务将是一个更好的地方,如果你愿意,你可以看看Omnipay

  • 您可以PaypalController过于抽象和AuthController将延长这一个(前提是你必须使用postPayment多个控制器内)。

  • 你可以做一个PaypalTrait并在你的AuthController中使用它(仅当你在多个控制器内部使用postPayment时)。

  • 当然,如果对您有意义,您可以将第一个解决方案与其他解决方案相结合。

这个问题有很多答案,我不认为完美的存在,它取决于你正在建设什么,你需要什么。

+0

其他人使用服务提供商提出改善这种设计,但我喜欢它的简单的特质想法。我对这两个概念都很陌生,但在我的情况下,这个特点是否合适?如果我理解正确,一个特点就是实现多重继承,并且Paypal处理被“继承”并不合适。你怎么看? – Obay

+0

是的,你可以做一个'CanProcessPayment' Trait并在需要处理PayPal的方法的每个Controller中使用它。但不要将其设置为静态,并重命名'initialize'方法以确保名称中没有碰撞...如果查看Laravel的BaseController,它会使用多个Traits来为每个控制器提供功能。抽象的PaypalController也不是一个糟糕的解决方案,就像特质一样,你只需要继承你的控制器就可以了。 – PeterPan666

1

这不是正确的做法。 Rember,控制器只应接收请求并将其发送给正确的服务,而不是自己处理buisness逻辑。

此规则适用:当你需要从另一个控制器调用控制器的方法它的气味的不良代码

相反,使用服务提供者和服务类来处理您的PayPal逻辑。服务类将处理PayPal的逻辑和稍后将用于当你需要它的控制器:

//SERVICE CLASS 
class PayPalService 
{ 
    public function processPayment(){ //... } 
} 

服务提供商用来注册应用程序的服务类:your're说服力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在控制自动注入服务的LER:

class AuthController extends Controller 
{ 
    public function postRegister(Request $request, PayPalService $paypal) { 
     return $paypal->processPayment(); 
    } 
} 

如果你愿意,你可以进一步通过使用接口,为服务类

+0

在你的最后一个例子中,你的意思是:'return $ paypal-> processPayment();'? – Obay

+0

@Obay:是的,谢谢:) – Moppo

相关问题