How to populate META and LINKS pagination on laravel? - php

I need help to populate this kind of pagination on laravel eloquent.
{
"meta": {
"count": 10,
"total": 100
},
"links": {
"first": "http://localhost/page[limit]=10&page[offset]=0",
"last": "http://localhost/page[limit]=10&page[offset]=10",
"next": "http://localhost/page[limit]=10&page[offset]=10",
"prev": "null"
},
"data": [
{
"type": "checklists",
"id": "1"
}
]
}
I have tried this code on Laravel Eloquent.
$data = Model::select('type','id')->paginate(10);
return response()->json(
[
'data' => $data
],200
);
But it shows different format, there is no META and LINKS schema on data populated.
{
"data": {
"current_page": 1,
"data": [
{
"type": "Mechanical Equipment Sales Representative",
"id": 1
}
],
"first_page_url": "http://localhost?page=1",
"from": 1,
"last_page": 4,
"last_page_url": "http://localhost?page=4",
"next_page_url": "http://localhost?page=2",
"path": "http://localhost",
"per_page": 10,
"prev_page_url": null,
"to": 10,
"total": 39
}
}
How to do that? Please help?

You can use API resources: https://laravel.com/docs/eloquent-resources#pagination
Create a collection resource:
php artisan make:resource ModelCollection
Use it in your controller:
$data = Model::select('type','id')->paginate(10);
return new ModelCollection($data);
For Lumen, create a app/Http/Resources/ModelCollection.php file:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class ModelCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

Related

Select * from a pivot table in laravel

I have a many to many relation with table users,items and the pivot table user_item and i need to call the query : Select * from user_item where user_id=$user->id in laravel and return the results in json format. I try with
$user=User::find(session('user_id'))->items()->get();
return response ()->json($user);
But it doesn't work. How can I do that?
class User extends Authenticatable {
public function items (){
return $this->belongsToMany ("App\Models\Item", "user_item", "user", "item");
}
}
class Item extends Models {
public function users (){
return $this->belongsToMany ("App\Models\User", "user_item", "item", "user");
}
}
You can define columns in your pivote table using withpivot method
public function items (){
return $this->belongsToMany ("App\Models\Item", "user_item",
"user", "item")->withPivot(['column1', 'column2','another_column']);
}
to get relation instead of using get(), you should use like below:
$user=User::find(session('user_id'))->items;
return response ()->json($user);
above will give below json result:
[{
"id": 4,
"name": "PC",
"pivot": {
"column1": 1,
"column2": 4,
"another_column": "2016-03-03"
}
},
{
"id": 5,
"name": "Phone",
"pivot": {
"column1": 1,
"column2": 4,
"another_column": "2016-03-03"
}
}]
you can also include pivot in use user model using with():
$user=User::with('items')->find(session('user_id'));
return response ()->json($user);
give json result something like:
{
"id": 1,
"name": "User Name",
"email": "email#user.com",
"created_at": null,
"updated_at": null,
"items": [{
"id": 4,
"name": "PC",
"pivot": {
"column1": 1,
"column2": 4,
"another_column": "2016-03-03"
}
},
{
"id": 5,
"name": "Phone",
"pivot": {
"column1": 1,
"column2": 4,
"another_column": "2016-03-03"
}
}]
}]

Laravel API Resource: How to return infinite nested array of categories with their children?

I use Laravel 6.x and below is my response JSON.
{
"data": [
{
"id": 1,
"name": "quam",
"parent_id": 0
},
{
"id": 2,
"name": "quia",
"parent_id": 1
},
{
"id": 3,
"name": "beatae",
"parent_id": 1
},
{
"id": 4,
"name": "aut",
"parent_id": 2
},
{
"id": 5,
"name": "provident",
"parent_id": 0
},
{
"id": 6,
"name": "voluptate",
"parent_id": 0
},
{
"id": 7,
"name": "vel",
"parent_id": 2
},
{
"id": 8,
"name": "sed",
"parent_id": 3
},
{
"id": 9,
"name": "voluptates",
"parent_id": 0
},
{
"id": 10,
"name": "adipisci",
"parent_id": 6
},
...
]
}
But it want to be like this:
{
"data": [
{
"id": 1,
"name": "quam",
"children": [
{
"id": 2,
"name": "quam"
"children":[
{
"id": 4,
"name": "aut"
},
{
"id": 7,
"name": "vel",
"children": [
...
]
}
]
},
{
"id": 3,
"name": "quam",
"children":[
{
"id": 8,
"name": "sed"
}
]
},
]
},
{
"id": 5,
"name": "provident"
},
{
"id": 6,
"name": "voluptate",
"children": [
{
"id": 10,
"name": "adipisci"
}
]
},
{
"id": 9,
"name": "voluptates"
},
...
}
In fact, I want to remove the parent_id attribute and add children array to each object that consists of other objects have this parent_id.
CategoryResource.php
class CategoryResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'parent_id' => $this->parent_id,
];
}
}
CategoryController.php
class CategoryController extends Controller
{
public function index()
{
return CategoryResource::collection(Category::all());
}
}
How can I implement this structure?
From what I see your problem is just the relations. To create a "tree resource" you have to load a lot of relations.
IMHO it's not a good choice, expecially if you have to load a lot of elements but generally, structures like these may be a dangerous bottleneck.
Anyway... The easy way it's the eager loading, so you have to add your base model with this attribute (have a look at the official documentation)
class Parent extends Model {
// [...]
/**
* The relationships that should always be loaded.
*
* #var array
*/
protected $with = ['children'];
// [...]
public function children() {
return $this->hasMany('whatever');
}
}
next you have to update your JSON Resource as follows (also for this, have a look at the official documentation about resource relationships).
class CategoryResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'parent_it' => $this->parent_id,
'childrend' => ChildrenResource::collection($this->whenLoaded('children')),
];
}
}
In this way, since everytime you request a Parent it will eager load its children, the resource will recursively map into a Child resource each relation down to the leaf.
Assuming Category is an eloquent model, Model's can reference themselves in relationships and those relationships can be recursive.
class Category extends Model
{
protected $hidden = ['parent_id'];
public function children()
{
return $this->hasMany('App\Category', 'parent_id')->with('children');
}
}
So now getting the structure you want is as simple as
Category::with('children:id,name,parent_id')->get('id', 'name', 'parent_id');
You have to include the parent_id in the select statement in order for the relationships to work but the $hidden variable I added to the model keeps parent_id from showing up in serialized results. The only caveat here is that all categories will have a children property, which will be empty for Categories that don't have children. So in your toArray method you will have to check for empty children[] and exclude them
First you need to define a relation for retrieving children of the main category which has no parents with this method
/**
* get sub product categories of this category
*
* #return mixed
*/
public function childCategories()
{
return $this->hasMany(Category::class,'parent_id');
}
Then you need to load the children of children categories with this method :
/**
* get recursive all sub categories of this category.
*
* #return mixed
*/
public function childrenCategories()
{
return $this->hasMany(Category::class,'parent_id')->with('childCategories');
}
Now you can retrieve them with this static function
/**
* get all Main categories with children.
*
* #return mixed
*/
public static function allMainCategoriesWithChildren()
{
return self::whereNull('parent_id')->with('childrenCategories')->get();
}
now you can use it in your resource or return it in controller directly
use App\Category;
return Category::allMainCategoriesWithChildren();

Hide attributes relationship from laravel eloquent resources collection

I'm trying to building API Resource and I wanna hide in collection the relationship attribute.
For example, I want to hide attribute 'permissions' only in RoleCollection. I mean I just only wanna hide this attribute in Collection, not Resource. Because Collection be called from Resource but I don't want to hide it in Resource.
Role.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Role extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'created_at' => $this->created_at->format('Y-m-d H:i:s'),
'updated_at' => $this->updated_at->format('Y-m-d H:i:s'),
'permissions' => Permission::collection($this->permissions),
];
}
}
RoleCollection.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class RoleCollection extends ResourceCollection
{
public function toArray($request)
{
return parent::toArray($request);
}
}
RoleController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Spatie\Permission\Models\Role;
use App\Http\Resources\Role as RoleResource;
use App\Http\Resources\RoleCollection;
class RoleController extends Controller
{
public function index()
{
$resource = Role::paginate();
return new RoleCollection($resource);
}
public function show($id)
{
$resource = Role::with('permissions')->find($id);
return new RoleResource($resource);
}
}
Response from: api/role/1
{
"data": {
"id": 1,
"name": "Super Administrador",
"created_at": "2019-05-07 16:45:38",
"updated_at": "2019-05-07 16:45:38",
"permissions": [
{
"id": 1,
"name": "user.list"
},
{
"id": 2,
"name": "user.view"
},
{
"id": 3,
"name": "user.save"
},
{
"id": 4,
"name": "user.delete"
}
]
}
}
Response from : /api/roles
{
"data": [
{
"id": 1,
"name": "Super Administrador",
"created_at": "2019-05-07 16:45:38",
"updated_at": "2019-05-07 16:45:38",
"permissions": [
{
"id": 1,
"name": "user.list"
},
{
"id": 2,
"name": "user.view"
},
{
"id": 3,
"name": "user.save"
},
{
"id": 4,
"name": "user.delete"
}
]
},
{
"id": 2,
"name": "Administrador",
"created_at": "2019-05-07 16:45:38",
"updated_at": "2019-05-07 16:45:38",
"permissions": []
}
],
"links": {
"first": "http://127.0.0.1:32773/api/roles?page=1",
"last": "http://127.0.0.1:32773/api/roles?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "http://127.0.0.1:32773/api/roles",
"per_page": 15,
"to": 2,
"total": 2
}
}
One way to do this is to use the whenLoaded method. The whenLoaded will return a MissingValue instance when a relationship has not been loaded. Laravel in turn will exclude this property from your resonse.
It is not only useful for hiding properties in certain responses, but also helps with performance. Currently your resource will do a query to fetch Permission models for every Role when this relationship was not loaded.
Your resource could look like:
return [
...
'permissions' => Permission::collection($this->whenLoaded('permissions')),
];
Laravel docs
One of the best way to handle this stuff is to use Fractals.
You can define a Transformer class for all your model, handle whether to include relationships or not every time you call them, and you can also define what attributes to show or to hide.
Basically you have one and only one point where your model can be serialized in JSON and you put all your logic there.
Also you can JSON-ize whole collections, through the single model transformers, very handy!

How to group same values in a parent array?

I want to create story for my ios app, I am trying to get useful json response for it. I want to show same user stories in a group inside of that user`s array.
Current JSON RESULT;
{
"current_page": 1,
"data": [
{
"id": 3,
"name": "Muhammed Ali Yüce",
"username": "ali",
"avatar": "1544128196.png",
"stories": {
"id": 3,
"user_id": 3,
"image": "1550228567.jpg",
"created_at": "2019-02-15 11:02:47",
"updated_at": "2019-02-15 11:02:47"
}
},
{
"id": 2,
"name": "Ömer Faruk YÜCE",
"username": "omer",
"avatar": "1544128227.png",
"stories": {
"id": 2,
"user_id": 2,
"image": "1550228407.jpg",
"created_at": "2019-02-15 11:00:08",
"updated_at": "2019-02-15 11:00:08"
}
},
{
"id": 2,
"name": "Ömer Faruk YÜCE",
"username": "omer",
"avatar": "1544128227.png",
"stories": {
"id": 1,
"user_id": 2,
"image": "1550072626.jpg",
"created_at": "2019-02-13 15:43:47",
"updated_at": "2019-02-13 15:43:47"
}
}
],
"first_page_url": "/?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "/?page=1",
"next_page_url": null,
"path": "/",
"per_page": 10,
"prev_page_url": null,
"to": 3,
"total": 3
}
I did tried groupBy func for it but it was not what I excepted.
I want to get result like this;
{
"id": 3,
"name": "Muhammed Ali Yüce",
"username": "ali",
"avatar": "1544128196.png",
"stories": [
{
"id": 2,
"user_id": 3,
"image": "1550228567.jpg",
"created_at": "2019-02-15 11:02:47",
"updated_at": "2019-02-15 11:02:47"
},
{
"id": 3,
"user_id": 3,
"image": "1550228567.jpg",
"created_at": "2019-02-15 11:02:47",
"updated_at": "2019-02-15 11:02:47"
}
]
StoryController.php
<?php
namespace App\Http\Controllers;
use App\Story;
use App\User;
use Illuminate\Http\Request;
use Image;
use Illuminate\Support\Facades\DB;
use Illuminate\Pagination\LengthAwarePaginator;
class StoryController extends Controller
{
public function index(Request $request){
$userId = $request->id;
$followsArr = [$userId];
$follows = DB::table('follows')->whereNotIn('ismuted', [1])->where('follower', $userId)->get();
foreach ($follows as $follow) {
$friend = $follow->following;
$followsArr[] = $friend;
}
$itemCollection = collect($followsArr);
$stories = [];
Story::whereIn('user_id', $itemCollection)
->orderBy('created_at', 'DESC')
->get()->each(function ($story) use (&$stories){
$user = User::where('id', $story->user_id)->first();
$stories[] =
['id' => $user->id]
+ ['name' => $user->name]
+ ['username' => $user->username]
+ ['avatar' => $user->avatar]
+ ['stories' => $story->toArray()];
});
// Get current page form url e.x. &page=1
$currentPage = LengthAwarePaginator::resolveCurrentPage();
// Create a new Laravel collection from the array data
$itemCollection = collect($stories);
// Define how many items we want to be visible in each page
$perPage = 10;
// Slice the collection to get the items to display in current page
$currentPageItems = $itemCollection->slice(($currentPage * $perPage) - $perPage, $perPage)->all();
// Create our paginator and pass it to the view
$paginatedItems= new LengthAwarePaginator($currentPageItems , count($itemCollection), $perPage);
return response()->json($paginatedItems);
}
I hope you will understand what I mean, Thanks in advance :)
Assume you have User.php and Story.php Models
In User.php
public function stories()
{
return $this->hasMany(Story::class);
}
You can load story along with user. something like that
$user = User::where('id', $story->user_id)->with('stories')->first(); //Eager Load
or
$user = User::where('id', $story->user_id)->first();
$user->load('stories'); //Lazy Eager Load
Please read more about Laravel Eloquent: Relationships

Add data into laravel object

so i have this kind of class from my user controller
public function index()
{
$table_data = User::with('CU','pus')->select('id','id_cu','id_pus','name','username','gambar','status','created_at')->filterPaginateOrder();
return response()
->json([
'model' => $table_data
]);
}
it is using trait called filterPaginateOrder and the end result that i receive are:
{
"model": {
"current_page": 1,
"data": [
{
"id": 8,
"id_cu": 0,
"id_pus": 1,
"name": "test1",
"username": "test17",
"gambar": "",
"status": 1,
"created_at": "2018-02-27 06:37:10",
"c_u": null,
"pus": {
"id": 1,
"name": "Puskopdit BKCU Kalimantan"
}
},
{
"id": 1,
"id_cu": 0,
"id_pus": 1,
"name": "tony",
"username": "t0n1zz",
"gambar": null,
"status": 1,
"created_at": "2017-01-01 11:11:11",
"c_u": null,
"pus": {
"id": 1,
"name": "Puskopdit BKCU Kalimantan"
}
}
],
"from": 1,
"last_page": 1,
"next_page_url": null,
"path": "https://bkcuvue.dev/api/v1/user",
"per_page": "2",
"prev_page_url": null,
"to": 2,
"total": 2
}
}
so what if i want to add some data into it? inside data array for each array i want to add "role":"master" how do i do that?
i tried $table_data->push('role','master') and $table_data->put('role','master') from reading about collection (those query in laravel return collection right?) but none of those code working...
There are two ways to go about it.
Add it via a foreach
$table_data = User::with('CU','pus')->select('id','id_cu','id_pus','name','username','gambar','status','created_at')->filterPaginateOrder();
foreach($table_data->data as $data) {
$data->role = 'master';
}
Or add it into the SELECT:
$table_data = User::with('CU','pus')->select('id','id_cu','id_pus','name','username','gambar','status','created_at', DB::raw('"master" as role'))->filterPaginateOrder();
Or you can override collection data of paginator object.
$table_data = User::with('CU','pus')->select('id','id_cu','id_pus','name','username','gambar','status','created_at')->filterPaginateOrder();
$table_data->getCollection()->each(function($user) {
$user->role = 'master';
});
return response()->json([
'model' => $table_data
]);

Categories