Laravel API 资源 可以是单个资源或集合。在某些情况下,需要将附加参数从控制器传递到资源/集合。下面是一个简单的示例,演示了使用
User
作为单个/集合资源以及要传递给资源以进行输出的自定义 $apple
参数的问题。该问题可以在下面的最终 Output (Collection)
中看到,对于 fruit
值,我们为第一个用户获得错误的 banana
值,而不是正确的 apple
值(所有其他用户都获得) 。它非常适合单个输出,但不适用于集合。见下图:
带有 UserResource 的控制器(单个)
$user = User::first();
return new UserResource($user, $apple = true); // $apple param passed
带有 UserResource(集合)的控制器
$users = User::limit(3)->get();
return UserResource::collection($users, $apple = true); // $apple param passed
用户资源
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource {
private $apple;
public function __construct($resource, $apple = false) {
// Ensure we call the parent constructor
parent::__construct($resource);
$this->resource = $resource;
$this->apple = $apple; // $apple param passed
}
public function toArray($request) {
return [
'id' => (int) $this->id,
'name' => $this->name,
'fruit' => $this->apple ? 'apple' : 'banana',
];
}
}
输出(单路)
{
"data": {
"id": 1,
"name": "Peter",
"fruit": "apple" // correct param!
}
}
输出(采集)
{
"data": [
{
"id": 1,
"name": "Peter",
"fruit": "banana" // INCORRECT param!
},
{
"id": 2,
"name": "Lois",
"fruit": "apple" // correct param!
},
{
"id": 3,
"name": "Brian",
"fruit": "apple" // correct param!
}
]
}
请注意,这只是一个示例,它可以是任意数量的随机参数(与
User
集合无关,但必须传递用于输出逻辑),例如来自不同表 I 的单个值 read_at
时间戳想要传递一次,并在输出之前在资源集合中对其执行一些逻辑(例如与用户时间戳进行比较),或者传递其他参数以在资源文件中执行其他逻辑if/else
,以操纵集合的输出。这怎么办?
以下方法对我有用:
用户资源
class UserResource extends Resource{
protected $foo;
public function foo($value){
$this->foo = $value;
return $this;
}
public function toArray($request){
return [
'id' => $this->id,
'name' => $this->name,
'foo' => $this->foo,
];
}
public static function collection($resource){
return new UserResourceCollection($resource);
}
}
用户集合
class UserResourceCollection extends ResourceCollection{
protected $foo;
public function foo($value){
$this->foo = $value;
return $this;
}
public function toArray($request){
return $this->collection->map(function(UserResource $resource) use($request){
return $resource->foo($this->foo)->toArray($request);
})->all();
// or use HigherOrderCollectionProxy
// return $this->collection->each->foo($this->foo)->map->toArray($request)->all()
// or simple
// $this->collection->each->foo($this->foo);
// return parent::toArray($request);
}
}
传递附加参数的不同方式
(new UserResource($user))->foo('bar');
(new UserResourceCollection($user))->foo('bar');
UserResource::make($user)->foo('bar');
UserResourceCollection::make($users)->foo('bar');
UserResource::collection($users)->foo('bar');
这就是我在 Laravel 8 上的制作方法。
class PatientResource extends JsonResource
{
private static $data;
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
//access $data
//self::$data
return [
'id' => $this->id,
'first_name' => $this->first_name,
'middle_name' => $this->middle_name,
'last_name' => $this->last_name,
'contact_number' => $this->contact_number
];
}
//I made custom function that returns collection type
public static function customCollection($resource, $data): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
{
//you can add as many params as you want.
self::$data = $data;
return parent::collection($resource);
}
}
然后在我的控制器上我调用了该自定义函数。
$data = PatientResource::customCollection($query->get(),$medicines);
您可以在调用 API 端点时传递额外的参数。然后,您可以使用 UserResource 中的 $request 对象(对于您的示例)访问参数。
例如,如果您使用以下内容从客户端(例如 Web 浏览器、axios 等)调用端点:
http://localhost:3000/api/users?apple=true
这将使参数 apple 的值为 true 在控制器中可用。您无需执行任何其他操作,也可以在 UserResource 的 toArray($request) 中访问它。您可以通过以下方式访问它:
public function toArray($request) {
$isApple = $request->apple;
return [
'id' => (int) $this->id,
'name' => $this->name,
'fruit' => $isApple ? 'apple' : 'banana',
];
}
这个简单的技巧在 Laravel 中对我有用:)
控制器
$user = User::find($user->id);
$user->access_token = $tokenResult->accessToken; // Add additional data
return new ProfileResource($user);
资源
public function toArray($request)
{
return [
'id' => $this->id,
'picture' => $this->picture,
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'active' => $this->active,
'access_token' => isset($this->access_token) ? $this->access_token : '', // Additional data
];
}
更新(2022 年 6 月)同样的逻辑也适用于集合
User.php(模型)
public static function getUserList(Request $request)
{
$output = [];
$query = User::query();
if ($request->has('search')) {
$query->where('first_name', $request->input('search'));
$query->orWhere('last_name', $request->input('search'));
$query->orWhere('email', $request->input('search'));
}
$queryActive = clone $query;
$queryInactive = clone $query;
$output = $query->paginate(config('services.PAGINATE_PER_PAGE'));
$statistics = [
'total' => $query->count(),
'inactive' => $queryInactive->where('status', 0)->count(),
'active' => $queryActive->where('status', 1)->count(),
];
$output->statistics = $statistics;
return $output;
}
用户控制器.php
public function index(Request $request): UserCollection
{
$users = User::getUserList($request);
return new UserCollection($users);
}
用户资源.php
namespace App\Http\Resources;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray($request)
{
return [
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'full_name' => $this->first_name . '' . $this->last_name,
'email' => $this->email,
'mobile' => $this->mobile,
'gender' => $this->gender,
'status' => $this->status,
'status_title' => $this->status ? 'Active' : 'Inactive',
'created_at_simple' => Carbon::parse($this->created_at)->format('Y-m-d'),
'created_at_simple_string' => Carbon::parse($this->created_at)->toFormattedDateString(),
'created_at' => Carbon::parse($this->created_at)->format('Y-m-d H:i:s'),
'created_at_ago' => Carbon::parse($this->created_at)->diffForHumans(),
'created_at_string' => Carbon::parse($this->created_at)->toDayDateTimeString(),
'updated_at_simple' => Carbon::parse($this->updated_at)->format('Y-m-d'),
'updated_at_simple_string' => Carbon::parse($this->updated_at)->toFormattedDateString(),
'updated_at' => Carbon::parse($this->updated_at)->format('Y-m-d H:i:s'),
'updated_at_ago' => Carbon::parse($this->updated_at)->diffForHumans(),
'updated_at_string' => Carbon::parse($this->updated_at)->toDayDateTimeString(),
'roles' => RoleResource::collection($this->roles),
];
}
}
用户集合.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
{
public function toArray($request)
{
return [
'data' => $this->collection,
'statistics' => [
'filters' => request()->all(),
'active' => $this->statistics['active'],
'inactive' => $this->statistics['inactive'],
'total' => $this->collection->count(),
],
];
}
}
为了与 Laravel 5.7 配合使用,我对 Wonka 的回答
做了一些更改用户资源
class UserResource extends Resource{
protected $foo;
public function foo($value){
$this->foo = $value;
return $this;
}
public function toArray($request){
return [
'id' => $this->id,
'name' => $this->name,
'foo' => $this->foo,
];
}
public static function collection($resource){
return new UserResourceCollection($resource, get_called_class());
}
}
用户集合
class UserResourceCollection extends AnonymousResourceCollection {
protected $foo;
public function foo($value){
$this->foo = $value;
return $this;
}
public function toArray($request){
return $this->collection->map(function(UserResource $resource) use($request){
return $resource->foo($this->foo)->toArray($request);
})->all();
}
}
我解决了我的问题,只需检索
中的
$request->get('param')
public function toArray($request){
$param = $request->get('param');
...
}
而不是通过资源传递参数。
你可以使用laravel 8
用于商店功能附加
return (UserResource::make(User::find($user->id)))
->additional([
'message'=>[
['user by name: '.$user->name.' created successfull.']
]
])->response()->setStatusCode(201);
您可以破解请求
在控制器中你有那个
request()->request->add([ 'extra_data' => [ 'foo' => 'foo-value', 'other' => 'something', ], ]);
在资源中
request()->get('extra_data') or $request->get('extra_data')
您不能在 API 资源
collection上使用
additional()
下面的示例不起作用✗
ProductSizeResource::collection()->additional(['stocks' => $this->stocks]);
您需要分别向每个资源附加附加数据
ProductSizeResource::collection(
$product->sizes->map(
fn(ProductSize $productSize) => (new ProductSizeResource($productSize))->additional(['stocks' => $this->stocks])
)
)