55

i have Post and User model with one to one relation and it works good:

//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's work 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:

```

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 am i wrong?

DaveIt
  • 799
  • 1
  • 8
  • 15

5 Answers5

141

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) like this :

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,
];
Maraboc
  • 10,550
  • 3
  • 37
  • 48
  • 1
    In my case, I was using a collection in collection resource. – Payam Khaninejad Jun 26 '18 at 07:26
  • thank you so much . I chose to use it instead of using it in the array: https://paste.laravel.io/198efba2-9954-4c9c-856e-e053e0d1f584 – melih sahin May 28 '19 at 14:21
  • @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? – basagabi Sep 07 '22 at 09:08
12

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)

runtimeTerror
  • 398
  • 3
  • 14
11

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)

runtimeTerror
  • 398
  • 3
  • 14
Amirex
  • 241
  • 3
  • 9
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())

elliot
  • 71
  • 1
  • 4
2

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,
    ];

}
}
Md Zahid
  • 440
  • 2
  • 8