Laravel Eloquent 4 table relationship - php

my database table structure
this my purchase model
class Purchase extends Model
{
public function supplierDetails(){
return $this->belongsTo('App\Supplier', 'supplier_id');
}
public function purchasedItems(){
return $this->hasMany('App\PurchasedItem', 'purchase_id');
}
}
this my controller method
public function getReport(){
$result = Purchase::with('supplierDetails', 'purchasedItems')->get();
return $result;
}
this is my json result
[
{
"id": 74,
"supplier_id": 3,
"invoice_no": "wds2",
"supplier_details": {
"id": 3,
"name": "alexy"
},
"purchased_items": [
{
"id": 114,
"purchase_id": 74,
"item_id": 2
},
{
"id": 115,
"purchase_id": 74,
"item_id": 3
}
]
}
]
i can make relationship between these Three models 'Supplier', 'Purchase', and 'PurchaseItem' but cannot make relationship with 'Item' models
i want json response like this
[
{
"id": 74,
"supplier_id": 3,
"invoice_no": "wds2",
"supplier_details": {
"id": 3,
"name": "alexy"
},
"purchased_items": [
{
"id": 114,
"purchase_id": 74,
"item_id": 2,
"item_details": {
"id": 2,
"name": "item1"
}
},
{
"id": 115,
"purchase_id": 74,
"item_id": 3,
"item_details": {
"id": 3,
"name": "item2"
}
}
]
}
]
Any idea?

This might help, i haven't tested but you should and let me know.
public function getReport(){
$purchases = Purchase::all;
$result;
foreach($purchases as $p){
$itemsPurchased = $p->purchasedItems;
foreach($itemsPurchased as $pitem){
$pitem['item_details'] = $pitem->YOUR.FUNCTION.NAME.FOR.ITEM.DETAILS.
}
$p['purchased_items'] = $itemsPurchased;
$p['supplier_details'] = $p->supplierDetails;
$result = array($p);
}
return $result;
}

i made some changes and the below code works..
public function getAll(){
$array = Purchase::with('supplierDetails', 'purchasedItems')->get();
$purchases = json_decode($array,true);
$result = array();
foreach($purchases as $p){
$itemsPurchased = $p['purchased_items'];
foreach($itemsPurchased as $pitem){
$pitem['item_details'] = PurchasedItem::with('itemDetails', 'packageDetails')->where('purchase_id', '=', $pitem['purchase_id'])->get();
}
$p['supplier_details'] = $p['supplier_details'];
$p['purchased_items'] = $pitem['item_details'];
array_push($result, array($p));
}
return $result;
//[0] added to remove []sqauare bracket
}

Related

send wrong object in laravel paginate collection

I use the below code for pagination an array so for the first page everything is fine and the response is shown correctly but for the next pages, I have a problem, in the paginated array add a key per each object that I didn't want that so how can I fix that?
public function currentOrders(Request $request)
{
$user = $request->user();
$orders = Order::with('address','foods')->where(['order_status'=>0,'user_id' => $user->id])->get();
$data=[];
if (sizeof($orders)>0) {
foreach ($orders as $order){
$tmp['date'] = Jalalian::forge($order->created_at)->format('%B %d، %Y');
$tmp['time'] = Jalalian::forge($order->created_at)->format('H:i');
$tmp['total'] = $order->sum_price;
$tmp['discount_pay'] = $order->price_off;
$address = Address::withTrashed()->whereId($order->address_id)->first();
$tmp['address'] = optional($address)->address;
$tmp['foods'] = [];
foreach ($order->foods as $food){
$price = 0;
$foodDetail = Article::withTrashed()->find($food->food_id);
$products = OrderItem::with('product')->where(['order_id'=>$food->order_id,'food_id'=>$food->food_id])->get();
$sec_tmp['products'] = [];
foreach ($products as $product){
$third_tmp['product_name'] = $product->product->title;
$third_tmp['count'] = $product->count;
$product_price = ($product->product->price->price_off ? $product->product->price->price_off : $product->product->price->customer_price) * $product->count;
$third_tmp['price'] = $product_price;
$price += $product_price;
array_push($sec_tmp['products'] ,$third_tmp );
}
$sec_tmp['food_name'] = $foodDetail->title;
$sec_tmp['food_count'] = $food->count;
$sec_tmp['food_price'] = $price * $food->count;
array_push($tmp['foods'],$sec_tmp);
}
array_push($data,$tmp);
}
}
$data_collection = collect($data);
$data_paginated = $this->paginate($data_collection);
return response()->json(['orders'=>$data_paginated]);
}
public function paginate($items, $perPage = 2, $page = null, $options = [])
{
$page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
$items = $items instanceof Collection ? $items : Collection::make($items);
return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}
my current result is
{
"orders": {
"current_page": 1,
"data": [
{
"date": "november 19، 2020",
"time": "01:38",
"total": 976400,
"discount_pay": 926400,
"address": "main st",
"foods": [
{
"products": [
{
"product_name": "oil",
"count": 3,
"price": 15000
},
{
"product_name": "egg",
"count": 5,
"price": 362000
},
{
"product_name": "fish",
"count": 1,
"price": 111200
}
],
"food_name": "sosage",
"food_count": 2,
"food_price": 976400
}
]
},
{
"date": "november 19، 2020",
"time": "01:43",
"total": 976400,
"discount_pay": 926400,
"address": "main street",
}
],
"first_page_url": "/?page=1",
"from": 1,
"last_page": 2,
"last_page_url": "/?page=2",
"next_page_url": "/?page=2",
"path": "/",
"per_page": 2,
"prev_page_url": null,
"to": 2,
"total": 4
}
}
but what I have in next pages is :
{
"orders": {
"current_page": 2,
"data": {
"1": {
"date": "november 19، 2020",
"time": "01:43",
"total": 976400,
"discount_pay": 926400,
"address": "main st",
"foods": [
{
"products": [
{
"product_name": "egg",
"count": 3,
"price": 15000
},
{
"product_name": "oil",
"count": 5,
"price": 362000
},
{
"product_name": "fish",
"count": 1,
"price": 111200
}
],
"food_name": "susage",
"food_count": 2,
"food_price": 976400
}
]
}
},
"first_page_url": "/?page=1",
"from": 2,
"last_page": 4,
"last_page_url": "/?page=4",
"next_page_url": "/?page=3",
"path": "/",
"per_page": 1,
"prev_page_url": "/?page=1",
"to": 2,
"total": 4
}
}
In the data object, there is a key like "1": { ... } and I want to be the same as the first page what should I do?
$data was an array but you get an object with key 1. it looks like the page number itself. But You're supposed to have a collection of $temp in $data;
You can check if $data_paginated['data'] is an array before returning return response()->json(['orders'=>$data_paginated]);
I think the error is on $this->paginate($data_collection) where $data_collection is a collection of items from list of $temp.
or could be on collect($data).
I see no error elsewhere.

PHP - How to get all children by Recursive?

show() function returns wrong data,why there is only one children
how to modify recursiveData function
Expectation result:
[
{
"id": 1,
"title": "p1",
"parentId": 0,
"children": [
{
"id": 5,
"title": "p1-child1",
"parentId": 1,
"children": [
{
"id": 13,
"title": "p5-child",
"parentId": 5,
"children": [
{
"id": 14,
"title": "p13-child",
"parentId": 13
}
]
}
]
},
{
"id": 6,
"title": "p1-child2",
"parentId": 1
}
]
},
{
"id": 2,
"title": "p2",
"parentId": 0,
"children": [
{
"id": 9,
"title": "p2-child1",
"parentId": 2
}
]
}
]
public function show()
{
$data = $this->getData(0);
$res = $this->recursiveData($data);
echo json_encode($res);
}
public function recursiveData($data)
{
if (empty($data)) {
return false;
}
$children = [];
foreach ($data as $dk => $dv) {
$children = $this->getData($dv['id']);
$data[$dk]['children'] = $children;
$this->recursiveData($children);
}
return $data;
}
/**
* Get data from database.
* #return array
**/
public function getData($parent_id)
{
$tmp = [];
$data = DB::select('select id,title from category where parent_id<99 and parent_id = ?', [$parent_id]);
foreach ($data as $dk => $dv) {
$tmp[] = [
'id' => $dv->id,
'title' => $dv->title,
'parentId' => $parent_id,
];
}
return $tmp;
}
At recursiveData()
modify
$data[$dk]['children'] = $children;
$this->recursiveData($children);
to
$data[$dk]['children'] = $this->recursiveData($children);

Laravel return json with eloquent collection relationship values

I have the following function inside the UsersApiController class :-
public function getKhatmas()
{
$user = Auth::user();
$khatmas = $user->khatmas;
return response()->json($khatmas);
}
The above code give the following response :-
[
{
"id": 3,
"hash": "5ec72b4913d1a",
"type": 2,
"type_text": "sample text",
"division": 2,
"division_variant": 1,
"status": "active",
"expiry_date": null,
"is_name": 0,
"user_id": 2,
},
{
"id": 4,
"hash": "5ec72b7005126",
"type": 2,
"type_text": "sample text",
"division": 2,
"division_variant": 1,
"status": "active",
"expiry_date": null,
"is_name": 0,
"user_id": 2,
},
]
Relationship function in User Model file :-
public function khatmas()
{
return $this->hasMany('App\Khatma');
}
App\Khatma file content :-
public function type()
{
return $this->belongsTo('App\KhatmaType');
}
In above json response , ("type": 2) is the foreign key of App\KhatmaType Model .
I want instead of json response with the foreign key of KhatmaType Model, i want it to return the column "title" from App\KhatmaType to be like this :-
{
"id": 3,
"hash": "5ec72b4913d1a",
"type": "this is title from App\KhatmaType Model",
"type_text": "sample text",
"division": 2,
"division_variant": 1,
"status": "active",
"expiry_date": null,
"is_name": 0,
"user_id": 2,
}
`I tried with the following :-
$khatmas = $user->khatmas->with('type');
But it return error : Method Illuminate\Database\Eloquent\Collection::with does not exist
Fixed by using the following query builder:-
public function getKhatmas()
{
$user = Auth::user();
$khatmas = Auth::user()->khatmas()
->select('hash','type_text','status','expiry_date','type_id')
->with('type')->get();
return response()->json($khatmas);
}

how to get proper nested json format?

I want to display the result of join query in nested JSON format but it will not work I am getting wrong input. I used two tables as
category_type={category_type_id,category_type_name,category_icon};
main_category={main_category_id,category_type_id,category_name}
I want display nested JSON result but not getting plz need solution.
Controller:
$data= DB::table('table_main_category')
->join('table_category_type','table_main_category.category_type_id','=','table_category_type.category_type_id')
->select('table_category_type.*','table_main_category.*')
->get();
return Response::json(array(
'success' => '1',
'data' => $data),
200
);
json output:
{
"success": "1",
"data": [
{
"category_type_id": 2,
"category_type": "Sports",
"category_icon": "http://192.168.1.132:8000/images/category/game.svg",
"main_category_id": 1,
"category_name": "Popular Sports"
},
{
"category_type_id": 2,
"category_type": "Sports",
"category_icon": "http://192.168.1.132:8000/images/category/game.svg",
"main_category_id": 2,
"category_name": "Team Sports"
}
]
}
required json:
"success": "1",
"data": [{
"category_type_id": 2,
"category_type": "Sports",
"category_icon": "http://192.168.1.132:8000/images/category/game.svg",
"main_category": {
"main_category_id": 1,
"category_name": "Popular Sports"
}
},
{
"category_type_id": 2,
"category_type": "Sports",
"category_icon": "http://192.168.1.132:8000/images/category/game.svg",
"main_category": {
"main_category_id": 2,
"category_name": "Team Sports"
}
}
]
A workaround could be to update the data before you send the Response:
foreach ($data->toArray() as $elem) {
$elem['main_category'] = [];
$elem['main_category']['main_category_id'] = $elem['main_category_id'];
unset($elem['main_category_id']);
// ... and so on
}
use this code to restructure your data :
$data= DB::table('table_main_category')
->join('table_category_type','table_main_category.category_type_id','=','table_category_type.category_type_id')
->select('table_category_type.*','table_main_category.*')
->get();
return Response::json(array(
'success' => '1',
'data' => $data.map( i => {
const {main_category_id ,category_name , ...j } = i ;
return ({...j , main_category: {
main_category_id,
category_name }
});
}) ,
200
);
You can use Eloquent relationship. First create your Models.
use Illuminate\Database\Eloquent\Model;
class MainCategory extends Model
{
public $table = 'table_main_category';
}
class CategoryType extends Model
{
public $table = 'table_category_type';
public function mainCategory()
{
return $this->belongsTo('App\MainCategory', 'category_type_id', 'category_type_id');
}
}
Then in your controller you can query it like
$data = CategoryType::with('mainCategory')->get();
This will load category types with their corresponding main categories

Modifiy response in laravel

Below my Laravel controller code
public function templateValueData($template_id)
{
$parent = TemplateMetadataValue::where('template_id', $template_id)->get();
return $parent;
}
Here, the output of the method above;
[
{
"id": 11,
"parent_id": 0,
"name": "Category 1"
},
{
"id": 63,
"parent_id": 11,
"name": "Category 2"
},
{
"id": 73,
"parent_id": 63,
"name": "Category 3"
},
{
"id": 77,
"parent_id": 11,
"name": "Category 5"
},
{
"id": 83,
"parent_id": 77,
"name": "Category 8"
}
]
Now I want to format this response base on the value of parent_id.
The condition is: when parent_id is equal to id, then the parent_id is considered as children of the id.
Please note that both parent_id and id are stored as incremental values.
I want to alter and return the response as below;
[
{
"id": 11,
"parent_id": 0,
"name": "Category 1",
"children": [
{
"id": 63,
"parent_id": 11,
"name": "Category 2",
"children": [
{
"id": 73,
"parent_id": 63,
"name": "Category 3"
}
]
},
{
"id": 77,
"parent_id": 11,
"name": "Category 5",
"children": [
{
"id": 83,
"parent_id": 77,
"name": "Category 8"
}
]
}
]
}
]
How can I achieve this?
Use below code for achieve your response.
public function templateValueData($template_id)
{
$parents = TemplateMetadataValue::where('template_id', $template_id)->get();
$arr = $this->xyz($parents);
return $arr;
}
Function for achieve response.
function xyz($parents,$parent_id = 0){
$res = [];
foreach ( $parents as $parent ) {
if ( $parent[ "parent_id"] == $parent_id ){
$children = $this->xyz($parents, $parent[ "id"]);
if ($children) {
$parent[ "children"] = $children;
}
$res[]=$parent;
}
}
return $res;
}
You should call your relation on your controller:
public function templateValueData($template_id)
{
$parent = TemplateMetadataValue::where('template_id',$template_id)->with('children')->get();
return $parent;
}
Also you can use method injection on your controller methods, so you can use this code:
public function templateValueData(TemplateMetadataValue $template)
{
return $template->load('children')->get();
}
If you slightly modify your TemplateMetadataValue model then you could achieve the desired result.
class TemplateMetadataValue extends Model {
public function children() {
return $this->hasMany(static::class, 'parent_id');
}
}
Call it with children method.
$parent = TemplateMetadataValue::with('children')->get();
Rest of the login you can apply here with your query builder.

Categories