[扩展推荐]在 Laravel 7 中使用 HTTP 客户端和数据传输对象
最近我在做一个项目,在 Laravel 7 中使用 HTTP 客户端从 Moodle (一个使用 PHP 开发的开源课程管理系统)中查询和显示数据。现在我想知道是否可以将查询到的数据从数组转换为更加可预测的对象。于是我问了我的同事,其中一位建议我看一下用于处理数据传输对象的 Spatie 软件包。
为了解释这个数据传输软件包的好处,我将使用比 Moodle 更简单的平台来说明这个问题。在一番搜索之后,我发现我们可以使用 JSONPlaceholder api (一个用于快速搭建 RESTful API 接口的平台)。
Laravel HTTP 客户端
Laravel 7 自带的 Http 客户端可以让你轻松地请求数据。我们可以像这样使用 Http 门面发送一个 get 请求,然后在后面使用 ->json()
方法返回 json。
use Illuminate\Support\Facades\Http;
$users = Http::get('https://jsonplaceholder.typicode.com/users')
->json();
dd($users);
如果你想在所有的请求中使用相同域名的话,我们可以在构造函数中使用 withOptions
方法并设置 base_uri
即可。这有助于让我们的代码变得更简洁,并使请求的行为更加明显。
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Http;
class ExampleController extends Controller
{
private $http;
public function __construct()
{
$this->http = Http::withOptions([
'base_uri' => 'https://jsonplaceholder.typicode.com/'
]);
}
public function index()
{
$users = $this->http->get('users')
->json();
dd($users);
}
}
如果你需要为你的每个请求都加上 Authorization Bearer Token 的话,只需在后面加上 withToken('my-token')
方法即可。
public function __construct()
{
$this->http = Http::withOptions([
'base_uri' => 'https://jsonplaceholder.typicode.com/'
])->withToken('my-token');
}
数据传输对象
现在我们得到了一个包含用户数据的数组,我们可以看看如何验证其中数据的类型。让我们先安装 数据传输对象 软件包。
composer require spatie/data-transfer-object
下面就是从 /users 接口中返回的用户信息。
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
}
我们可以创建一个类把得到的用户数据映射到其中,你可以将该类放在任何地方,在本例中,我将会在 app/Objects 目录下创建一个名为 User 的类。这个类需要继承 Spatie\DataTransferObject\DataTransferObject
。然后我们需要将用户数据中的每个属性以变量的形式定义在该类中,并在每个变量上面定义它是什么类型的数据。
<?php
namespace App\Objects;
use Spatie\DataTransferObject\DataTransferObject;
class User extends DataTransferObject
{
/** @var integer */
public $id;
/** @var string */
public $name;
/** @var string */
public $username;
/** @var string */
public $email;
/** @var array **/
public $address;
/** @var string */
public $phone;
/** @var string */
public $website;
/** @var array **/
public $company;
}
像下面这样将用户数据映射到这个类中。
$users = $this->http->get('users')
->json();
$user = new \App\Objects\User($users[0]);
这个软件包为我们做了一些非常有用的事情。
- 如果返回的数据不是我们定义的类型,将返回一个异常(比如 id 是 null 而不是整型)。
- 如果你期望的属性(如 userName )不在 json 中,将抛出一个异常。
- 如果返回的其他属性不在你的对象中,也将抛出一个异常。
当你尝试在程序中使用数据之前,这可以帮助确保返回你所期望的数据。因为不可预测的数据会在应用程序中引起各种问题。
嵌套使用数据传输对象
现在我们只能验证 address 和 company 是否为数组,但是如果我们想验证它们内部的每个数据的类型该怎么办呢?我们可以通过为 address 和 company 创建一个类来使其更加具体。
下面是 Address 类,它还有另外一个 Geo 属性,同理,你也需要创建一个 Geo 的类。
<?php
namespace App\Objects;
use Spatie\DataTransferObject\DataTransferObject;
class Address extends DataTransferObject
{
/** @var string */
public $street;
/** @var string */
public $suite;
/** @var string */
public $city;
/** @var string */
public $zipcode;
/** @var \App\Objects\Geo */
public $geo;
}
现在我们可以在 User 类中将刚刚创建的 Address 类填写在 $address
上方。
// app/Objects/User.php
/** @var \App\Objects\Address */
public $address;
这将确保 address 的数据遵循我们在 Address 类中的定义。
如果一个用户有多个 address ,那么我们可以在 Address 后面添加一个 [],使其期望一个数组。
// app/Objects/User.php
/** @var \App\Objects\Address[] */
public $address;
请注意,这里我使用的是完整的命名空间。这是自动嵌套类型转换所必需的。
使用对象
现在我们已经定义了我们的对象,并确保了类型转换的正确性,我们可以以调用对象的方式使用数据,并知道数据将是什么类型。
$users = $this->http->get('users')
->json();
$user = new \App\Objects\User($users[0]);
var_dump($user->id); // int(1)
var_dump($user->name); // string(13) "Leanne Graham"
var_dump($user->address->street); // string(11) "Kulas Light"
最后,希望你能看到 Laravel Http 客户端和 Spatie 数据传输对象给你的程序带来的好处。
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
Objects with their own Data Transfer Objects
这个该怎么翻译好一点呢?
他的意思应该是用自己(这里指已经定义了数据传输对象的User)的对象接着定义数据传输对象。
有没有大神能帮我组织下语言,想不出来怎么写的简洁通顺