Laravel API Resource Collection return specific fields from other resource - laravel

I am working on an api that will be accessible via a mobile app.
I have defined resources and collections for respective endpoints. My problem is now is that I want to return different api json data based on what ever collection.
Here is an example
Provinces has cities and suburbs, so in json format I need to have
"data": [
{
"id": 1,
"name": "Eastern Cape",
"cities": [
{
"name": "Alice"
},
],
"suburbs": [
"name": "Suburb 1"
]
},
]
I want different data when the cities resource is called in news api collection
"data": [
{
"id": 1,
"name": "Eastern Cape",
"cities": [
{
"name": "Alice",
"municipality": "municipality name",
},
],
"suburbs": [
"name": "Suburb 1",
"ward_number": "ward 1"
]
},
]
This is an NewsResource Api
public function toArray($request)
{
// return parent::toArray($request);
return [
'id'=> $this->id,
'title' => $this->title,
'slug' => $this->slug,
'content' => $this->content,
'created_at' => $this->created_at,
'category_id' => $this->news_category_id,
'featured_image' => url($this->featured_image),
'author' => new UserResource($this->user),
'category' => new NewsCategoryResource($this->category), //Only category Name to be displayed
'municipality' => new MunicipalityResource($this->municipality), // Only Municipality Name to be displayed
'comments' => new NewsCommentResource($this->comments),
];
}

I don't really know what is your code structure, but hope this help for you
You may use different queries, for example
/** For the obvious resource calling */
return SomeResource::collection (SomeModel::with(['suburbs', 'cities'])
/** Other filter queries */
->get());
/** For the cities resource calling */
return SomeResource::collection (SomeModel::with(['suburbs:id,ward_number', 'cities:id,municipality'])
/** Other filter queries */
->get());
In your Resource class which you use for the cities/suburbs data, do it like so
return [
/** Some data which you need */
'municipality' => $this->when($this->municipality !== null, $this->municipality),
'ward_number' => $this->when($this->ward_number !== null, $this->ward_number),
];

Related

L8 - API - Form Request on optional input JSON object

I'm working on Form Request and I've a question about how to use it with optional input object.
My API get a simple input JSON like:
{
"user": [
{
"name": "Valentino",
"car": {
"model": "ferrari",
"color": {
"front": "red",
"back": "black"
}
}
},
"name": "Stefano",
"car": {
"model": "mercedes"
}
}
]
}
the Controller:
public function insertUser(StoreUserRequest $request) {
}
the For Request Validation Class:
public function rules()
{
return [
'user' => 'required|array',
'user.*.name' => 'string|required',
'user.*.car' => 'required|array',
'user.*.car.model' => 'required|string',
'user.*.car.color' => 'nullable|array', // could be present or not
'user.*.car.color.front' => 'required|string', // should be validated only if exists 'color'
'user.*.car.color.back' => 'required|string', // should be validated only if exists 'color'
];
}
the color object could be optional into the input JSON; how I can set StoreUserRequest.php class to validate the color object only if exists?
Thank you very much!
#Tippin tell me a solution using required_with rule:
public function rules()
{
return [
'user' => 'required|array',
'user.*.name' => 'string|required',
'user.*.car' => 'required|array',
'user.*.car.model' => 'required|string',
'user.*.car.color' => 'nullable|array', // could be present or not
'user.*.car.color.front' => 'required_with:user.*.car.color|string',
'user.*.car.color.back' => 'required_with:user.*.car.color|string',
];
}
Thanks

Laravel API Resource not returning data with one to many relationship

In my DoctorController, I have show method like below -
public function show(Doctor $doctor){
DoctorResource::withoutWrapping();
return new DoctorResource($doctor->load('expertises'));
}
In my DoctorResource, if I do
public function toArray($request){
return parent::toArray($request);
}
It returns -
{
"id": 1,
"name": "John Doe",
"mobile": "1234567890",
"email": null,
"avatar": null,
"bio": "Lorem Ipsum 2",
"email_verified_at": null,
"mobile_verified_at": null,
"is_account_verified": 0,
"account_status": "Active",
"created_at": "2020-12-03T07:45:07.000000Z",
"updated_at": "2020-12-03T10:49:30.000000Z",
"expertises": [
{
"id": 1,
"expertise": "ABC",
"created_at": null,
"updated_at": null,
"pivot": {
"doctor_id": 1,
"expertise_id": 1,
"created_at": "2020-12-03T10:49:29.000000Z",
"updated_at": "2020-12-03T10:49:29.000000Z"
}
},
{
"id": 2,
"expertise": "XYZ",
"created_at": null,
"updated_at": null,
"pivot": {
"doctor_id": 1,
"expertise_id": 2,
"created_at": "2020-12-03T10:49:29.000000Z",
"updated_at": "2020-12-03T10:49:29.000000Z"
}
}
]
}
But I want to return certain fields from my DoctorResource, So I did this but it is giving me an error. Exception: Property [expertise] does not exist on this collection instance.
public function toArray($request){
return [
'id' => $this->id,
'name' => $this->name,
'mobile' => $this->mobile,
'email' => $this->email,
'avatar' => $this->avatar,
'bio' => $this->bio,
'expertises' => [
'name' => $this->expertises->expertise
]
];
}
you have define another Json Resource to do that:
first you can retrive the model and add keys and values based on each model properties like :
public function toArray($request){
return [
'id' => $this->id,
'name' => $this->name,
'mobile' => $this->mobile,
'email' => $this->email,
'avatar' => $this->avatar,
'bio' => $this->bio,
'expertises' => ExpertiesResource::collection($this->experties);
];
}
and you have to define Resource Collection as Follow:
class ExpertiesResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
"id" => $this->id,
"exp" => $this->exp,
.....
];
}
}
when your JsonResource has an Array of Object(Resource), you have to Define That Resource and make use of it like use App\Http\Resources\ExpertiesResource

Laravel: How to access Object inside an array

I trying to return access the attributes inside a array of object and it is giving this error Exception: Property [id] does not exist on this collection instance.
Here is what I have tried:
protected function formatted($classroom)
{
return [
'courses' => [
'id' => $classroom->courses->id,
'name' => $classroom->courses->name,
'slug' => $classroom->courses->slug,
'coursteachers' => [
'id' => '$classroom->courses->coursteachers->id',
'email' => '$classroom->courses->coursteachers->email',
'uid' => '$classroom->courses->coursteachers->uid',
]
],
];
}
And here is the actual data:
"courses": [
{
"id": 1,
"name": "Analytics",
"slug": "analytics",
"status_id": 1,
"deleted_at": null,
"pivot": {
"classroom_id": 2,
"courses_id": 1
},
"coursteachers": [
{
"id": 3,
"uid": "S0120-46890",
"email": "teacher#vschool.com",
"user_type": "Teacher",
}]
}]
You need to iterate through courses and also courseteachers since they both represent an array but rather an object
protected function formatted($classroom)
{
$result = [];
foreach($classroom->courses as $course) {
$result[] = [
'courses' => [
'id' => $classroom->courses->id,
'name' => $classroom->courses->name,
'slug' => $classroom->courses->slug,
'coursteachers' => $this->getCourseTeachers($cours)
],
];
}
return $result;
}
private function getClassroomTeachers($classroom) {
$result = [];
foreach($classroom->courses as $cours)
{
foreach ($cours->coursteachers as $key => $teacher) {
$result[] = [
// 'coursteachers'=> [
'id' => $teacher->id,
'email' => $teacher->email,
'uid' => $teacher->uid,
'last_name' => $teacher->profile->last_name,
'first_name' => $teacher->profile->first_name,
'middle_name' => $teacher->profile->middle_name,
// ],
];
}
}
return $result;
}
Since courses is an array, you should pick an object using the proper index.
Foe example: try $classroom->courses[0]->id instead of $classroom->courses->id. Here, '0' is the index.
Also it is better if you check if the index exists before you do it. For an example.
'id' : isset($classroom->courses[$index]) ? $classroom->courses[$index]->id : ''
Edit:
In case of a Eloquent collection you should use $classroom->courses->get($index)->id instead of array like retrieval.

Laravel Spatie Permissions - user and role relation get only id and name

I'm using Laravel Spatie Permissions to manage roles and permissions in my app. I'm traing to retrieve only Role id and name in the relation between users and roles. My UserResource looks like this:
class UserResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'surname' => $this->surname,
'email' => $this->email,
'inactive' => $this->inactive,
'roles' => $this->roles
];
}
}
And the json looks like this:
"data": [
{
"id": 1,
"name": "Admin",
"surname": "Sudo",
"email": "admin#sudo.com",
"inactive": 0,
"roles": [
{
"id": 1,
"name": "Admin",
"guard_name": "web",
"created_at": "2020-05-28 23:18:58",
"updated_at": "2020-05-28 23:18:58",
"pivot": {
"model_id": 1,
"role_id": 1,
"model_type": "App\\User"
}
}
]
},
]
What I really need it's a json like this:
"data": [
{
"id": 1,
"name": "Admin",
"surname": "Sudo",
"email": "admin#sudo.com",
"inactive": 0,
"roles": [
{
"id": 1,
"name": "Admin",
},
{
"id": 2,
"name": "Default",
},
{
"id": 3,
"name": "Guest",
}
]
},
]
I really don't know how to modified my models relations or the parameter $this->roles (in UserResources) to could get this json.
The easiest solution was using a map function:
'roles' => $this->roles->map(function($role){
return [
'id' => $role['id'],
'name' => $role['name']
];
})
You can create a RoleResource:
class RoleResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
];
}
}
And use it on your UserResource:
class UserResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'surname' => $this->surname,
'email' => $this->email,
'inactive' => $this->inactive,
'roles' => RoleResource::collection($this->roles),
];
}
}

Laravel 5.8 ManyToMany relationship child relation usign foreign key doesn't work

When I call my image resource it returns the correct data from my model:
Image resource:
return [
'id' => $this->id,
'name' => $this->name,
'presentation' => $this->presentation->description,
'slug' =>$this->filename
];
Image Model:
public function presentation()
{
return $this->hasOne(ProductPresentation::class, 'id', 'presentation_id');
}
Returns:
{
"data": [
{
"id": 1,
"name": "White Gold",
"presentation": "Product x",
"slug": "products/white-gold.jpg"
}
}
But when I call the manyToMany (Products -> images) relation I only get the the Id not the foreign relation
"data": [
{
"id": 1,
"name": "White Gold",
"price": "€ 10,00",
"images": [
{
"id": 1,
"name": "White Gold",
"filename": "products/white-gold.jpg",
"presentation_id": 1
}
]
},
The Products resource calls the image resource but this doesn't load the relation ( need "presentation": "Product x" instead of "presentation_id": 1)
Using resource:
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->formattedPrice,
'images' => $this->images
];
using model:
public function images()
{
return $this->belongsToMany(Image::class);
}
So the question would be how do I add the relation to belongsToMany(Image::class)
Try to change
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->formattedPrice,
'images' => $this->images
];
To
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->formattedPrice,
'images' => YourImageResource::collection($this->images)
];

Resources