Laravel get single item from Array in Query with relation ship - php

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);
}

Related

Laravel - best way to update huge amount of data from request?

I have an ecommerce application developed using laravel. Every day I want to update an amount of products from external api (request).
Response:
[
{
"id": 1,
"code": "0564",
"amount": 200
},
{
"id": 2,
"code": "4235",
"amount": 24
},
{
"id": 3,
"code": "27683",
"amount": 646
},
{
"id": 4,
"code": "457",
"amount": 44
},
]
Below laravel function in controller:
public function import(Request $request)
{
$products = $request->all();
foreach ($products as $product) {
$currentProduct = Product::where('code', $product['code'])->first();
if ($currentProduct) {
$currentProduct->amount = $product['amount'];
$currentProduct->update();
}
}
return response()->json([
'status' => 'success',
], Response::HTTP_OK);
}
Above code is working, but it is slower. Is there any best way to do this?
You Can Use
public function import(Request $request)
{
$products = $request->all();
foreach ($products as $product) {
Product::where('code', $product['code'])
->update(['amount'=>$product['amount']]);
}
return response()->json([
'status' => 'success',
], Response::HTTP_OK);
}
if you are using (Laravel >= 8.x) there is a method named upsert. The method's first argument consists of the values to insert or update, while the second argument lists the column(s) that uniquely identify records within the associated table. The method's third and final argument is an array of columns that should be updated if a matching record already exists in the database.
try something like this:
public function import(Request $request)
{
$data = $request->all();
foreach (array_chunk($data, 500) as $products) {
$updateData = [];
foreach($products as $value) {
$currentProduct = Product::where('code', $value['code'])->first();
if ($currentProduct) {
$updateData[] = [
'code' => $value['code'],
'amount' => $value['amount'],
];
}
}
Product::upsert($updateData, ['code'], ['amount']);
}
return response()->json([
'status' => 'success',
], Response::HTTP_OK);
}

Conditionaly Laravel Resource

TicketResource.php
public function toArray($request) {
return [
'id' => $this->id,
'user_id' => $this->user_id,
'title' => $this->title,
'body' => $this->body,
'status' => $this->status,
'created_at' => $this->created_at->toDateTimeString(),
];
}
CommentResource.php
public function toArray($request) {
return [
'id' => $this->id,
'body' => $this->body,
'user_id' => $this->user_id,
'created_at' => $this->created_at->toDateTimeString()
];
}
TicketController.php
public function index() {
return TicketResource::collection(Ticket::all());
}
public function show(Ticket $id) {
$ticket = $id;
return new TicketResource($ticket);
}
Model Ticket.php
public function comments() {
return $this->hasMany('App\Comment');
}
Model Comment.php
public function ticket() {
return $this->belongsTo('App\Ticket');
}
routes/api.php
Route::get('tickets', 'TicketController#index');
Route::get('tickets/{id}', 'TicketController#show');
I want when I request to tickets/{id} URL, I expect to receive this response:
{
"data": {
"id": 1,
"user_id": 2,
"title": "lorem",
"body": "epsum",
"status": "open",
"created_at": "2020-03-04 18:14:56",
"comments": [
{
"id": 1,
"body": "equi",
"user_id": 1,
"created_at": "2020-03-05 18:14:56",
}
]
}
}
On the contrary, when I visit tickets URL, I don't want the comments to be added on each ticket.
How can I implement that?
You need to add relation
This is my model class:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function children()
{
return $this->hasMany(Category::class, 'parent_id', 'id')->select('categories.id',
'categories.cid AS key',
'categories.name AS label',
'categories.type',
'categories.lvl');
}
}
in my controller:
$parents = Category::select(
'categories.id',
'categories.id AS key',
'categories.name AS label')->where('lvl', 1)->get();
foreach ($parents as $item) {
$item->children
}
return Response::json($parents, 200, array('Content-Type' => 'application/json;charset=utf8'), JSON_UNESCAPED_UNICODE);
Result:
[
{
"id":2,
"key":2,
"label":"parent label",
"children":[
{
"id":17,
"key":"92697f63-5c50-11ea-80df-5cf9ddf839d3",
"label":"child label",
"type":"Category",
"lvl":2,
}
]
}
]

Laravel paginate resources won't add meta

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.'
];
}

Laravel Api Resource

I'm trying to create an API for my data tables using Laravel's resource. I have three models with relationships. Every time I hit my api routes to check the result I'm getting a null value in my sub_specializations. Here's the result already JSON formatted.
{
"data":[
{
"first_name":"Rusty",
"last_name":"Ferry",
"specializations":{
"specialization_id":11,
"specialization_name":"Endocrinology"
},
"sub_specializations":null
},
{
"first_name":"Nadia",
"last_name":"Ondricka",
"specializations":{
"specialization_id":22,
"specialization_name":"ENT"
},
"sub_specializations":null
},
{
"first_name":"Erich",
"last_name":"Torphy",
"specializations":{
"specialization_id":2,
"specialization_name":"Cardiologist"
},
"sub_specializations":null
}
]
}
Here are all my resources. This the DoctorsResource
public function toArray($request)
{
return [
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'specializations' => new SpecializationsResource($this->specializations),
'sub_specializations' => new SubSpecializationsResource($this->sub_specializations),
];
}
Specializations Resource
public function toArray($request)
{
return [
'specialization_id' => $this->specialization_id,
'specialization_name' => $this->specialization_name,
];
}
SubSpecializations
public function toArray($request)
{
return [
'sub_specialization_id' => $this->sub_specialization_id,
'sub_specialization_name' => $this->sub_specialization_name,
'doctors' => new DoctorsResource($this->doctors),
];
}
Lastly, this is the controller
protected $user;
public function __construct(Doctors $doctors){
$this->doctors = $doctors;
}
public function index()
{
$doctors = $this->doctors->with('specializations', 'subSpecializations')->get();
return DoctorsResource::collection($doctors);
}
The result that I'm expecting is similar to this
{
"data":[
{
"first_name":"Rusty",
"last_name":"Ferry",
"specializations":{
"specialization_id":11,
"specialization_name":"Endocrinology"
},
"sub_specializations": {
"sub_specialization_name":"value"
}
}
]
}
You have to make sure there is data of Sub Specializations for particular doctor.
If there is data then add that data to Doctor Resource otherwise it will be blank.
Just need to change line in doctor Resource like:
'sub_specializations' => $this->sub_specializations !== null ? new SubSpecializationsResource($this->sub_specializations) : '',
You can do same thing with specializations also.

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

Categories