Une Laravel API Resource peut être une ressource unique ou une collection. Dans certains cas, des paramètres supplémentaires doivent être transmis à la ressource/collection à partir du contrôleur. Vous trouverez ci-dessous un exemple simple illustrant le problème en utilisant User
comme ressource unique/collection et un paramètre $Apple
personnalisé à transmettre à la ressource pour la sortie. Le problème peut être vu dans la dernière Output (Collection)
ci-dessous, où pour la valeur fruit
, nous obtenons une valeur incorrecte de banana
pour le premier utilisateur, au lieu de la valeur correcte Apple
(que tous les autres utilisateurs obtiennent). Cela fonctionne parfaitement pour la sortie unique, mais pas pour la collection. Voir ci-dessous:
Contrôleur avec UserResource (Single)
$user = User::first();
return new UserResource($user, $Apple = true); // $Apple param passed
Contrôleur avec UserResource (Collection)
$users = User::limit(3)->get();
return UserResource::collection($users, $Apple = true); // $Apple param passed
UserResource
<?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',
];
}
}
Sortie (Simple)
{
"data": {
"id": 1,
"name": "Peter",
"fruit": "Apple" // correct param!
}
}
Sortie (Collection)
{
"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!
}
]
}
Veuillez noter qu'il ne s'agit que d'un exemple. Il peut s'agir d'une quantité quelconque de paramètres aléatoires (sans lien avec la collection User
, mais doit être transmise pour la logique de sortie), telle qu'une valeur unique read_at
timestamp d'une table différente que je souhaite transmettre une fois, et effectuez une logique dessus dans la collection de ressources avant la sortie (comme une comparaison avec un horodatage utilisateur), ou d'autres paramètres passés pour que la logique supplémentaire if/else
soit exécutée dans le fichier de ressources en général afin de manipuler la sortie de la collection. Comment cela peut-il être fait?
L'approche suivante a fonctionné pour moi:
UserResource
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);
}
}
UserCollection
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);
}
}
Différentes façons de passer le paramètre supplémentaire
(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');
Vous pouvez transmettre les paramètres supplémentaires dans le cadre de l'appel du point de terminaison de l'API. Vous pouvez ensuite accéder aux paramètres avec l'objet $ request (pour votre exemple) dans UserResource.
Par exemple, si vous appelez le noeud final à partir d'un client, tel qu'un navigateur Web, axios, etc., utilisez l'une des méthodes suivantes:
http://localhost:3000/api/users?apple=true
cela rendra le paramètre Apple avec une valeur true disponible dans le contrôleur. Sans aucune autre action de votre part, il sera alors également accessible dans le toArray ($ request) de UserResource. Vous pouvez y accéder semblable à:
public function toArray($request) {
$isApple = $request->Apple;
return [
'id' => (int) $this->id,
'name' => $this->name,
'fruit' => $isApple ? 'Apple' : 'banana',
];
}
Pour travailler avec Laravel 5.7, j'ai apporté quelques modifications par rapport à la réponse de Wonka
UserResource
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());
}
}
UserCollection
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();
}
}