在我的应用中,我安装了此软件包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
来做到这一点?如果是这样的话,正确的方法是什么?
答案 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
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客户端而言,这很有意义。
答案 2 :(得分:0)
是的,服务是放置通用代码的好地方-控制器应该使用该服务,而不是相互调用
很难举一个例子,但是我尝试在您的情况下解释该怎么做:代替create ExternalController创建externalRequestsService,它将准备数据并使用枪口将请求发送到外部API,并且在您的控制器中仅使用该服务。