使用正确的工具扩展Laravel软件包

时间:2019-01-22 16:27:54

标签: laravel laravel-5

在我的应用中,我安装了此软件包https://github.com/guzzle/guzzle以发出http/curl个请求。

然后我创建了一个ExternalController来扩展Guzzle Package的功能,如下所示:

namespace App\Http\Controllers;

use GuzzleHttp\Client as GuzzleHttpClient;
use GuzzleHttp\Exception\ClientException as ClientException;

class ExternalController extends Controller
{
    protected $endpoint = '';
    protected $method   = '';

    public function __construct()
    {
        $this->debug = env("APP_DEBUG", false);
    }

    /**
     * Crypts Server call
     */

    public function encodeCall($method = 'GET', $endpoint = "server_status")
    {
        $EXTERNAL_PROTOCOL         = config('myconfig.EXTERNAL_PROTOCOL');
        $EXTERNAL_IP               = config('myconfig.EXTERNAL_IP');
        $EXTERNAL_PORT             = config('myconfig.EXTERNAL_PORT');
        $EXTERNAL_MANAGEMENT_TOKEN = config('myconfig.EXTERNAL_MANAGEMENT_TOKEN');

        //Skip some parameters for security reasons

        $base64hash                = base64_encode($str2hash);

        $request_url = "${EXTERNAL_PROTOCOL}://${EXTERNAL_IP}:${EXTERNAL_PORT}/manage/${endpoint}?salt=${salt}&hash=${base64hash}";

        $requestContent = [
            'headers' => [
                'Accept'       => 'application/json',
                'Content-Type' => 'application/json',
            ],
        ];

        try {

            $client   = new GuzzleHttpClient();
            $curl     = $client->request($method, $request_url, $requestContent);
            $response = json_decode($curl->getBody());

            return response()->json($response);

        } catch (RequestException $RequestException) {

            return response()->json(['message' => (string) $ClientException]);

        }
    }

    /**
     * Returns Server Status
     * @return \Illuminate\Http\Response
     */
    public function getServerStatus()
    {
        $method   = 'GET';
        $endpoint = "server_status";

        return $this->encodeCall($method, $endpoint);
    }

}

我处于需要从另一个控制器调用某些方法的情况,例如:

//AnotherController.php

$server = new ExternalController;
return $server->getServerStatus();

我通常不会在另一个Controller中调用一个Controller,但是我对Laravel的了解不足以了解什么是正确的工具。

我是Laravel的新手,所以也许我需要创建一个ServiceProvider来做到这一点?如果是这样的话,正确的方法是什么?

3 个答案:

答案 0 :(得分:2)

听起来像您需要服务。我可以将共享代码放入服务中,然后从其他控制器/命令/作业/等处调用它。

服务

namespace App\Services;

class MyService
{
  public function getStatus()
  {
    return 'foo';
  }
}

控制器A

namespace App\Http\Controllers;

use App\Services\MyService;

class MyController extends Controller
{
  public function __construct(MyService $myService)
  {
    $this->myService = $myService;
  }

  public function index()
  {
     $response = $this->myService->getStatus();
  }
}

控制器B

namespace App\Http\Controllers;

use App\Services\MyService;

class MyOtherController extends Controller
{
  public function __construct(MyService $myService)
  {
    $this->myService = $myService;
  }

  public function index()
  {
     $response = $this->myService->getStatus();
  }
}

答案 1 :(得分:2)

您绝对可以从另一个控制器调用一个控制器。

但是,这不是控制器的本意。在您的特定情况下,您创建了一个HTTP客户端,很可能在多个地方使用它。

这就是我要做的。首先,我将在App\Services\Http

中定义一个HttpClientContract
namespace App\Services\Http;

interface HttpClientContract
{
/**
    * Crypts Server call
    */
    public function encodeCall($method = 'GET', $endpoint = 'server_status');

    /**
    * Returns Server Status
    * @return \Illuminate\Http\Response
    */
    public function getServerStatus();

}

..然后我将实现如下:

namespace App\Services\Http;

use GuzzleHttp\Client as GuzzleHttpClient;
use GuzzleHttp\Exception\ClientException as ClientException;

class HttpClient implements HttpClientContract
{
    protected $endpoint = '';
    protected $method   = '';

    public function __construct()
    {
        $this->debug = env('APP_DEBUG', false);
    }

    public function encodeCall($method = 'GET', $endpoint = 'server_status')
    {
        $EXTERNAL_PROTOCOL         = config('myconfig.EXTERNAL_PROTOCOL');
        $EXTERNAL_IP               = config('myconfig.EXTERNAL_IP');
        $EXTERNAL_PORT             = config('myconfig.EXTERNAL_PORT');
        $EXTERNAL_MANAGEMENT_TOKEN = config('myconfig.EXTERNAL_MANAGEMENT_TOKEN');

        //Skip some parameters for security reasons

        $base64hash                = base64_encode($str2hash);

        $request_url = "${EXTERNAL_PROTOCOL}://${EXTERNAL_IP}:${EXTERNAL_PORT}/manage/${endpoint}?salt=${salt}&hash=${base64hash}";

        $requestContent = [
            'headers' => [
                'Accept'       => 'application/json',
                'Content-Type' => 'application/json',
            ],
        ];

        try {

            $client   = new GuzzleHttpClient();
            $curl     = $client->request($method, $request_url, $requestContent);
            $response = json_decode($curl->getBody());

            return response()->json($response);

        } catch (RequestException $RequestException) {

            return response()->json(['message' => (string) $ClientException]);

        }
    }

    public function getServerStatus()
    {
        $method   = 'GET';
        $endpoint = "server_status";

        return $this->encodeCall($method, $endpoint);
    }

}

最后,我们需要在应用程序的服务容器中注册新的Http Client。 我们将使用服务提供商来实现此目标:

<?php

namespace App\Providers;

use App\Services\HttpClient;
use App\Services\HttpClientContract;
use Illuminate\Support\ServiceProvider;

class HttpClientServiceProvider extends ServiceProvider
{
    /**
    * Register bindings in the container.
    *
    * @return void
    */
    public function register()
    {
        $this->app->bind(HttpClientContract::class, function ($app) {
            return new HttpClient();
        });
    }
}

我们还需要将此新服务提供商添加到我们的容器中。 因此,在config/app.php$providers数组中,您需要添加以下内容:

'providers' => [
    //
    //

    App\Services\Http\HttpClientServiceProvider::class
]

现在,每当需要使用它时,只需要从容器中解决它即可。如果您在方法中键入依赖项,Laravel将使用反射通过容器自动解析它。

public function makeRequest(HttpClientContract $client)
{
    return $client->encodeCall(); 
}

通过这种方式,我们正在应用一些OOP原则。 首先,我们是“编码到接口”而不是实现。

如果将来您对HTTP客户端的实现发生变化,则只需绑定新客户端即可。

我们还将注入依赖项到我们的方法中,而不是在方法内部实例化它。这样,我们就可以在测试过程中交换/模拟HTTP客户端的实现,对于HTTP客户端而言,这很有意义。

详细了解Service ProvidersService Container

答案 2 :(得分:0)

是的,服务是放置通用代码的好地方-控制器应该使用该服务,而不是相互调用

很难举一个例子,但是我尝试在您的情况下解释该怎么做:代替create ExternalController创建externalRequestsService,它将准备数据并使用枪口将请求发送到外部API,并且在您的控制器中仅使用该服务。