61

I have Post and User model with one to one relation and it works well:

//User.php

public function post(){
    return $this->hasOne(Post::class);
}


// Post.php

public function user() {
    return $this->belongsTo(User::class);
}

now I create API resources:

php artisan make:resource Post
php artisan make:resource User

I need to return all post with an API call then I set my route:

//web.php: /resource/posts

Route::get('/resource/posts', function () {
    return PostResource::collection(Post::all());
});

This is my Posts resource class:

<?php

namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
use App\Http\Resources\User as UserResource;

class Posts extends Resource
{
/**
 * Transform the resource into an array.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return array
 */
public function toArray($request)
{
      return [
        'id' => $this->id,
        'title' => $this->title,
        'slug' => $this->slug,
        'bodys' => $this->body,
        'users' => UserResource::collection($this->user),
        'published' => $this->published,
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];
  
}
}

This is the error:

Call to undefined method Illuminate\Database\Query\Builder::mapInto()

if I remove:

'users' => UserResource::collection($this->user),

it works but I need to include relations in my API JSON, I have read and followed the doc at https://laravel.com/docs/5.5/collections.

This is my User resource class:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\Resource;

class User extends Resource
{
/**
 * Transform the resource into an array.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return array
 */
public function toArray($request)
{
   return [
       'user_id' => $this->user_id,
       'name' => $this->name,
       'lastname' => $this->lastname,
       'email' => $this->email
   ];
}
}

Any ideas where I am wrong?

6 Answers 6

155

The problem is that you use UserResource::collection($this->user) and you have just one element not a collection so you can replace it with new UserResource($this->user) or you can the static metod way UserResource::make($this->user) like this :

return [
    'id' => $this->id,
    'title' => $this->title,
    'slug' => $this->slug,
    'bodys' => $this->body,
    'users' => new UserResource($this->user), // or UserResource::make($this->user)
    'published' => $this->published,
    'created_at' => $this->created_at,
    'updated_at' => $this->updated_at,
];
Sign up to request clarification or add additional context in comments.

3 Comments

In my case, I was using a collection in collection resource.
thank you so much . I chose to use it instead of using it in the array: paste.laravel.io/198efba2-9954-4c9c-856e-e053e0d1f584
@runtimeTerror also mentioned the use of the static method make like so: UserResource::make($this->user). I would like to know what's difference between the two aside from the later is using a static method?
14

this problem is that you use UserResource::collection($this->user) it mean you have many users but and you have just one element for the a single resource and not a collection so you can replace it with new UserResource($this->user)

Comments

13

In Laravel 8.5.*, you can use the static method make on the collection to get the same result. It would be like UserResource::make($this->user)

Comments

6

when you have just one element and not a collection use new Resouce

return [
        'id' => $this->id,
        'name' => $this->name,
        'description' => $this->description,
        'user' => new UserResource($this->whenLoaded('user')),
];

and give a try to use the eager loading for better perfomance not just this. using the method whenLoaded and put the relations name in ( ).

Resource::collection is used when the model has hasMany relation. If your model has hasOne relation use Resource::make(Book::all())

Comments

5

The issue is that you use UserResource::collection($this->user) and you have just one element come from database, not list of collection. It would be solved if you used new UserResource($this->user) like this:

<?php

namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
use App\Http\Resources\User as UserResource;

class Posts extends Resource
{
/**
 * Transform the resource into an array.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return array
 */
public function toArray($request)
{
      return [
        'id' => $this->id,
        'title' => $this->title,
        'slug' => $this->slug,
        'bodys' => $this->body,
        'users' => new UserResource($this->user),
        'published' => $this->published,
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];

}
}

Comments

1

use make instead of collection; because your relation is belongTo (one to one) and it is one record ** is not a collection** .when relation is hasMany or morphTomany use collection. use

UserResource::make($this->user)

instead

UserResource::collection($this->user)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.