Laravel 5.6 - 将附加参数传递给 API 资源?

问题描述 投票:0回答:9

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
,以操纵集合的输出。这怎么办?

laravel-5 laravel-5.6
9个回答
59
投票

以下方法对我有用:

用户资源

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');

21
投票

这就是我在 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);

11
投票

您可以在调用 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',
        ];
    }

9
投票

这个简单的技巧在 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(),
            ],
        ];
    }
}

4
投票

为了与 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();

        }
    }

3
投票

我解决了我的问题,只需检索

 中的 
$request->get('param')

public function toArray($request){ 

   $param = $request->get('param');

   ... 

} 

而不是通过资源传递参数。


2
投票

你可以使用laravel 8

用于商店功能附加

    return (UserResource::make(User::find($user->id)))
            ->additional([
                'message'=>[
                    ['user by name: '.$user->name.' created successfull.']
                ]
            ])->response()->setStatusCode(201);

2
投票

您可以破解请求

在控制器中你有那个

request()->request->add([ 'extra_data' => [ 'foo' => 'foo-value', 'other' => 'something', ], ]);

在资源中

request()->get('extra_data') or $request->get('extra_data')

0
投票

您不能在 API 资源

collection
上使用 additional()

下面的示例不起作用✗

ProductSizeResource::collection()->additional(['stocks' => $this->stocks]);

您需要分别向每个资源附加附加数据

ProductSizeResource::collection(
   $product->sizes->map(
       fn(ProductSize  $productSize) => (new ProductSizeResource($productSize))->additional(['stocks' => $this->stocks])
   )
)
© www.soinside.com 2019 - 2024. All rights reserved.