基于以上原因,我们需要一个中间层,在我们输出model成为JSON的时候,可以进行一次信息的过滤及加工。
那么还是使用我们上面的应用场景。要输出自定义的字段再简单不过了。我们不需要在model里定义各种accessor,也不需要使用黑白名单过滤字段,只需要新建一个Resource类:
$ php artisan make:resource Customer
然后我们可以看到,在app/Http文件夹下,多出了一个名为Resources文件夹下,其中含有一个名为Customer.php的文件:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class Customer extends JsonResource { /** * Transform the resource into an array. * * @param \Illuminate\Http\Request $request * @return array */ public function toArray($request) { return parent::toArray($request); } }
这里我们看到其中有且仅有一个名为toArray的方法。这就是我们要自定字段的地方:
public function toArray($request) { return [ 'fullName' => $this->first_name . $this->last_name, 'fullShippingAddress' => $this->shippingAddress->country->name . $this->shippingAddress->province->name . $this->shippingAddress->city->name . $this->shippingAddress->address, ]; }
注意到,无论是fullName还是fullShippingAddress,都是不存在于customers表中的字段。
接着,我们只需要简单修改一下我们的控制器:
<?php namespace App\Http\Controllers; use App\Customer; use App\Http\Resources\Customer as CustomerResource; use App\Http\Controllers\Controller; class CustomerController extends Controller { /** * Simple function to fetch all customers with their shipping addresses * * @return String */ public function index() { $customers = Customer::with(['shippingAddress', 'shippingAddress.country', 'shippingAddress.province', 'shippingAddress.city'])->get(); //这里我们使用了新的Resource类 return CustomerResource::collection($customers); } }
这样就OK了!我们输出的JSON数据中,将会仅仅含有以上两个字段,即fullName和fullShippingAddress,非常干净,并且前端直接可用,不需要二次再加工。
唯一需要注意的是,这里由于我们拉取了多个Customer,所以我们用了每个Resource类都自带有的collection方法,将一个Collection中的所有对象都进行处理。而若要处理单个对象,我们需要使用以下代码:
public function show($id) { $customer = Customer::findOrFail($id); return new CustomerResource($customer); }
要了解更多关于API Resources的详情,请戳官网文档: