laravel APi resource Call to undefined method Illuminate\Database\Query\Builder::mapInto() - laravel

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?

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

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)

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)

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())

Related

Laravel JsonResource return specific key

<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'description' => $this->description,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
Sometimes I need to return some specific key instead whole resource.
How to return a specific array of key from JsonResource toArray()? like Request with only(['key1', 'key4']) function.
From your controller, when you pass data to your view or API, you simply specify the exact key you want to access.
For example, in your controller
public function store(Request $request){
//You other logic here
$post = new PostResource( $request->all() );
//Here, you return only the specific key you want to access
return response([
'title' => $post->title,
]);
}
All the best

Laravel Resource return value from another Resource?

I tried to find a solution here but nothing worked. I want to return values from TagResource using MealResource because I have TagTranslations table and I'm getting the data from the table with translations in TagResource.
Relationships are correctly formed, meal and tag models are connected via meal_tags table and tagtranslations belongsTo Tag::class.
I used TagResource like this:
class TagResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
$translation = $this->translations->where('tag_id', $this->id)->first();
return
[
'id' => $this->id,
'title' => $translation->title,
'slug' => $translation->slug,
];
}
}
and MealResource like this:
public function toArray($request)
{
$translation = $this->translations->where('meal_id', $this->id)->first();
$category_translation = $this->category->translations->where('category_id', $this->category->id)->first();
return [
'id' => $this->id,
'title' => $translation->title,
'decription' => $translation->description,
'category' => [
'id' => $this->category->id,
'title' => $category_translation->title,
'slug' => $category_translation->slug,
],
'tags' => FILL IN THE BLANK (have used TagResource:collection() and new TagResource()) and didnt work
];
}
public function toArray($request)
{
$translation = $this->translations->where('meal_id', $this->id)->first();
$category_translation = $this->category->translations->where('category_id', $this->category->id)->first();
return [
'id' => $this->id,
'title' => $translation->title,
'decription' => $translation->description,
'category' => [
'id' => $this->category->id,
'title' => $category_translation->title,
'slug' => $category_translation->slug,
],
'tags' => TagResource::collection($this->tags),
];
}
If all the Relationships namings/mappings are correct then this will work.And please make sure that model are perfectly mapped respectively.

How can I do API Resources pagination?

I created an API and made customizations. Looking through the documentation, I tried a few ways, but somehow I could not do the pagination. Can you help me?
PostResource.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'image' => $this->image,
'description' => $this->description,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'user' => new UserResource($this->user),
'comments' => CommentResource::collection($this->comment),
];
}
}
PostController.php
public function res() {
$post_all_item = Posts::all();
return response()->json(PostResource::collection($post_all_item),200);
}
This is how you can paginate collections in laravel:
$post_all_item = Posts::paginate(15); //will paginate 15 posts per page
return PostResource::collection($post_all_item); //will be converted to Json automatically
Note1: Model names should be singularis eg. Post instead of Posts
Note2: Its not necessary to convert a resource collection to json response, Laravel will do that automatically
Note3: In resource files, check if relationships exists by using whenLoaded:
'user' => new UserResource($this->whenLoaded('user')), //with resource
'comments' => $this->whenLoaded('comments'), //without resource

Laravel resources when called in usersController gives me a different path and an error

I am a week old into laravel and am working on my first api.
Everything worked well till I decided to introduce resources. When I call the UserResource method I get an error that I can't understand. I have googled but haven't found an answer yet.
This is the error I get when I run on postman
Symfony\Component\Debug\Exception\FatalThrowableError: Call to undefined function App\Http\Controllers\Api\UserResource()
The Resource file is in app/Http/Resources/
Checkout the path returned
App\Http\Controllers\Api\UserResource
yet the one I add is
App\Http\Resources\UserResource;
Laravel Code:
app/Http/Controllers/Api/usersController.php
use App\User;
use App\Http\Resources\UserResource;
class UsersController extends Controller
{
public function login(Request $request)
{
$this->validate($request, [
'email' => 'required',
'password' => 'required',
]);
$email = $request->email;
$password = $request->password;
$user = User::where('email', $email)->where('password', $password)->first();
if($user) {
$success['token'] = $user->createToken('myapp')-> accessToken;
$success['user'] = UserResource($user);
return response()->json(['success' => $success], 200);
}
return response()->json(['error' => 'UnAuthorised'], 401);
}
}
app/Http/Resources/UserResource.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
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,
'first_name' => $this->first_name,
'other_names' => $this->other_names,
'email' => $this->email,
'phone_number' => $this->phone_number,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
You forgot the new operator trying to instantiate the UserResource class. Without the new operator, PHP will look for a function called UserResource in the current namespace, therefore you get that error.

Laravel: Too few arguments to function 0 passed and exactly 1 expected"

I know this has been asked before. ive seen the questions and answers but cant find something that I can get help from.
I am trying to pass simple data into my database. so far so good.
I believe my problem arises when I try to add the userID since it has to be pulled from Auth. so here is my controller code.
side node , userID is from a foreign table called users. and userID will be used as a foreign key. in the userstable its called "id"
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ShopController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('/shop/addShop');
}
protected function validator(array $data)
{
return Validator::make($data, [
'userid' => ['required', 'string', 'max:255'],
'shopname' => ['required', 'string', 'max:255'],
'address' => ['required', 'string', 'max:255'],
'postal' => ['required', 'string', 'max:255'],
'city' => ['required', 'string', 'max:255'],
'phone' => ['required', 'string', 'max:255'],
]);
}
/**
* Add Users shop after a validation check.
*
* #param array $data
* #return \App\
*/
protected function create(array $data)
{
$userId = Auth::id();
return User::create([
'userid'=> $data[$userId],
'shopname' => $data['shopname'],
'address' => $data['address'],
'postal' => $data['postal'],
'city' => $data['city'],
'phone' => $data['phone'],
]);
}
}
and right here you can see my route.
<?php
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
Route::post('/addShop', 'ShopController#create')->name('addShop');
Route::get('/addShop', 'ShopController#index')->name('addShop');
Use Request
Your create function is expecting an array. However, Laravel is passing a POST request. Therefore, use the Request class instead. Your code should read:
namespace App\Http\Controllers;
use User;
use Illuminate\Http\Request;
protected function create(Request $data)
{
$userId = Auth::id();
return User::create([
'userid'=> $data[$userId],
'shopname' => $data['shopname'],
'address' => $data['address'],
'postal' => $data['postal'],
'city' => $data['city'],
'phone' => $data['phone'],
]);
}
I got this error on my project it was because this line of code
Auth::guard()->logoutOtherDevices(); I just comment it and my logout function worked correctly.

Resources