Laravel paginate resources won't add meta - php

I have resources data returning in JSON. When I try to get my data with paginate it is not included meta data.
Based on documentation my data supposed to be included meta like:
"meta":{
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "http://example.com/pagination",
"per_page": 15,
"to": 10,
"total": 10
}
but my data is returning like this:
Code
controller
public function index()
{
$products = ProductFrontResource::collection(Product::orderby('id', 'desc')->with(['photos', 'seo', 'tags', 'variations', 'variations.children', 'options', 'options.children', 'categories'])->where('active', 'yes')->paginate(8));
return response()->json([
'data' => $products,
'message' => 'Products retrieved successfully.',
]);
}
Any idea?

You don't need to use response(). Laravel's resource classes allow you to expressively and easily transform your models and model collections into JSON.
Every resource class defines a toArray method which returns the array of attributes that should be converted to JSON when sending the response.
public function index()
{
$data = Product::orderby('id', 'desc')
->with(['photos', 'seo', 'tags', 'variations', 'variations.children', 'options', 'options.children', 'categories'])
->where('active', 'yes')
->paginate(8);
$products = ProductFrontResource::collection($data);
return $products;
}
Additional Meta Data
'message' => 'Products retrieved successfully.'
Yes, you can Adding Meta Data.
public function toArray($request)
{
return [
'data' => $this->collection,
'message' => 'Products retrieved successfully.'
];
}

Related

Laravel get single item from Array in Query with relation ship

in my one of models such as posts i have a column array as featured_image and when i get result query from this model that return all of this array items, for example:
"featured_image": {
"images": {
"original": "/uploads/post_images/2020/1598873165.jpg",
"300": "/uploads/post_images/2020/300_1598873165.jpg",
"900": "/uploads/post_images/2020/900_1598873165.jpg"
},
"thumbnail": "/uploads/post_images/2020/300_1598873165.jpg"
},
now how can i modify this below query to get only one item from this array such as thumbnail?
public function allData()
{
$posts = Post::with(['groups', 'categories' => function ($query) {
$query->whereLocked(false);
}])->wherePublished(true)->get();
return response()->json([
'posts' => $posts,
], 200);
}
you can try this :
public function allData()
{
$posts = Post::with(['groups', 'categories' => function ($query) {
$query->whereLocked(false);
}])->wherePublished(true)
->select('{primary must included to use With}', 'other', 'columns', 'featured_image->thumbnail as thumbnail')
->get();
return response()->json([
'posts' => $posts,
], 200);
}

A relation between 3 tables Laravel

I'm trying to create an API resource, where I can view a response build from three tables.
Store
Orders
Purchases
Currently, I can go to a store (there are multiple stores) using routes (api/store/orders) and view the orders in a JSON response.
response
{
data: [
{
id: 1,
code: "1f",
status: "waiting",
user_name: "Salman",
created_at: "",
updated_at: ""
},
{
id: 2,
code: "2f",
status: "waiting",
user_name: "Jerome",
created_at: "",
updated_at: ""
}
]
}
However, when I try to add my purchases to the response with:
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Orderresource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'code' => $this->code,
'status' => $this->status,
'user_name' => $this->user_name,
// Added purchases
'order' => $this->purchases,
'created_at' => (string) $this->created_at,
'updated_at' => (string) $this->updated_at,
];
}
}
I get met with an error response Undefined property: stdClass::$purchases
Now I've added purchases to my order model with:
public function purchases()
{
return $this->hasMany(Purchase::class);
}
However, I know that the order may lie with my show_order_per_store.
function in my OrderController
public function show_order_per_club($id)
{
$order = DB::table('orders')->where('store_id', '=', $id)->get();
return Orderresource::collection($order);
}
Now, this function gets all orders with similar stores, but how do I add the purchases to the stores API response?
In short, I'm trying to get an API response per store with the orders it has, and the purchases belong to that order.
Instead of using DB:table for querying, try using the model directly:
Order::where('store_id', '=', $id)->get();
Seems DB:table returns stdClass objects, so it lacks all the virtual attributes that a model might provide.

don't return the object if relation array is empty

UPDATED
I have eloquent object
$storeCollections = StoreCollection::where('op_city_id', $opCity->id)
->where('isVisible', true)
->has('storeCollectionStores','>', 0)
->with([
'storeCollectionStores' => function ($query) use ($storeIds) {
$query->whereIn('store_id', $storeIds)->with(['store' => function ($query){
$query->select('id', 'ref', 'tagline', 'type', 'budget', 'cover', 'has_manager',
'timezone', 'priority', 'op_city_id', 'currency_id', 'ref_translation', 'tagline_translation')
->with([
'currency',
'storeTags.tag',
'labels' => function ($query) {
$query->select('id', 'label', 'store_id', 'label_translation');
},
]);
}])
->orderBy('priority', 'asc');
}
])
->orderBy('priority')
->get();
I'm getting empty array if storeCollectionStore is empty..
I want to remove the whole collection if the relation is empty
any suggestions?
result is like this
"storeCollections": [
{
"id": 9,
"title": "Our Favorites",
"desc": "Choose from our all-time favorite stores",
"priority": 0,
"isVisible": true,
"op_city_id": 1,
"created_at": "2018-11-08 11:11:18",
"updated_at": "2018-11-08 11:11:18",
"title_ar": "المفضلة لدينا",
"desc_ar": "اختر من بين جميع المتاجر المفضلة على",
"store_collection_stores": []
},
You can either apply a filter on the outer collection to check if the inner storeCollectionStores collection has elements.
$filteredCollection = $collection->filter(function($store) {
return $store->storeCollectionStores->count() > 0;
});
You could also just use whereHas() with a similar closure to your with() on the query itself. whereHas limits the query results, with loads the related data. You need to use both to filter and load.
https://laravel.com/docs/5.7/eloquent-relationships#querying-relationship-existence
you could use whereHas method to put "where" conditions on your has queries like this:
$storeCollections = StoreCollection::where('op_city_id', $opCity->id)
->where('isVisible', true)
->whereHas('storeCollectionStores')
...
These methods allow you to add customized constraints to a relationship constraint
Read the docs here

Laravel pagination append data in one variable and other in another variable

I am facing a problem in laravel pagination. In laravel when I called paginate() method it returns
{
"total": 50,
"per_page": 15,
"current_page": 1,
"last_page": 4,
"first_page_url": "http://laravel.app?page=1",
"last_page_url": "http://laravel.app?page=4",
"next_page_url": "http://laravel.app?page=2",
"prev_page_url": null,
"path": "http://laravel.app",
"from": 1,
"to": 15,
"data":[
{
// Result Object
},
{
// Result Object
}
]
}
This type of Object. What I want is that I want to set data in one vairable for example $a and except data all other value in $b.
But when I added appends('data') of my paginate variable it did not working correctly. I did not find a solution after googling it. Please help me to solve this.
Here is User model
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Authenticatable {
use Notifiable;
use SoftDeletes;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password', 'status', 'role_id',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
My Controller Code is
public function index() {
$users = User::where('status', 1)->paginate(10);
return response()->json(
[
'error' => 0,
'errorMsg' => '',
'data' => [
'users' => $users->appends('data')->toArray(),
],
]
);
}
I tried this code
return response()->json(
[
'error' => 0,
'errorMsg' => '',
'data' => [
'users' => $users->only($user['data'])->toArray(),
'users_pagination' => $users->except($user['data'])->toArray(),
],
]
);
In this users work correctly but users_pagination not working correctly. In both the users, users_pagination returns same value
Try this
$paginateData = User::where('status', 1)->paginate(10);
$arrPaginateData = $paginateData->toArray();
$users = $arrPaginateData['data'];
unset($arrPaginateData['data']); //remove data from paginate array
$pageInfo = $arrPaginateData;
Return in response
return response()->json(
[
'error' => 0,
'errorMsg' => '',
'data' => [
'users' => $users,
'users_pagination' => $pageInfo
],
]
);
Why not try to iterate the object? the below code will attached user specific data into each users.
public function index() {
$users = User::where('status', 1)->paginate(10);
foreach($users as $users){
$users->data = 'your data here';
}
return response()->json([
'error' => 0,
'errorMsg' => '',
'data' => [
'users' => $users,
],
]
);
}
If you want to use Laravel appends you have to follow as per the document.

Eloquent automatically selects unwanted columns upon eager-loading model relationship

I am converting an internal API from HTML (back-end) processing to JSON (using Knockout.js) processing on the client-side to load a bunch of entities (vehicles, in my case).
The thing is our database stores sensitive information that cannot be revelead in the API since someone could simply reverse engineer the request and gather them.
Therefore I am trying to select specifically for every relationship eager-load the columns I wish to publish in the API, however I am having issues at loading a model relationship because it seems like Eloquent automatically loads every column of the parent model whenever a relationship model is eager loaded.
Sounds like a mindfuck, I am aware, so I'll try to be more comprehensive.
Our database stores many Contract, and each of them has assigned a Vehicle.
A Contract has assigned an User.
A Vehicle has assigned many Photo.
So here's the current code structure:
class Contract
{
public function user()
{
return $this->belongsTo('User');
}
public function vehicle()
{
return $this->belongsTo('Vehicle');
}
}
class Vehicle
{
public function photos()
{
return $this->hasMany('Photo', 'vehicle_id');
}
}
class Photo
{
[...]
}
Since I need to eager load every single relationship listed above and for each relationship a specific amount of columns, I need to do the following:
[...]
$query = Contract::join('vehicles as vehicle', 'vehicle.id', '=', 'contract.vehicle_id')->select([
'contract.id',
'contract.price_current',
'contract.vehicle_id',
'contract.user_id',
'contract.office_id'
]);
[...]
$query = $query->with(['vehicle' => function ($query) {
$query->select([
'id',
'trademark',
'model',
'registration',
'fuel',
'kilometers',
'horsepower',
'cc',
'owners_amount',
'date_last_revision',
'date_bollo_expiration',
'bollo_price',
'kilometers_last_tagliando'
]);
}]);
$query = $query->with(['vehicle.photos' => function ($query) {
$query->select([
'id',
'vehicle_id',
'order',
'paths'
])->where('order', '<=', 0);
}]);
$query = $query->with(['user' => function ($query) {
$query->select([
'id',
'firstname',
'lastname',
'phone'
]);
}]);
$query = $query->with(['office' => function ($query) {
$query->select([
'id',
'name'
]);
}]);
[...]
return $this->response->json([
'error' => false,
'vehicles' => $vehicles->getItems(),
'pagination' => [
'currentPage' => (integer) $vehicles->getCurrentPage(),
'lastPage' => (integer) $vehicles->getLastPage(),
'perPage' => (integer) $vehicles->getPerPage(),
'total' => (integer) $vehicles->getTotal(),
'from' => (integer) $vehicles->getFrom(),
'to' => (integer) $vehicles->getTo(),
'count' => (integer) $vehicles->count()
],
'banner' => rand(0, 2),
'filters' => (count($input) > 4),
'filtersHelpText' => generateSearchString($input)
]);
The issue is: if I do not eager load vehicle.photos relationship, columns are loaded properly. Otherwise, every single column of Vehicle's model is loaded.
Here's some pictures so you can understand:
Note: some information have been removed from the pictures since they are sensitive information.
You can set a hidden property on your models which is an array of column names you want to hide from being output.
protected $hidden = ['password'];

Categories