Set key to difference key when get laravel relationship - php

I want to change my collection array key to language code.
Here is my code
$products = Product::has('languages')->paginate(20);
return response()->json($products);
This is my relationship
public function languages($lang_id = null)
{
if ($lang_id)
return $this->hasMany(ProductLang::class)->where('lang_id', $lang_id)->first();
return $this->hasMany(ProductLang::class);
}
This is what I get for now.
Illuminate\Database\Eloquent\Collection {#613 ▼
#items: array:2 [▼
0 => App\Models\Product\ProductLang {#614 ▶}
1 => App\Models\Product\ProductLang {#615 ▶}
]
}
Expected:
Illuminate\Database\Eloquent\Collection {#613 ▼
#items: array:2 [▼
en => App\Models\Product\ProductLang {#614 ▶}
zh => App\Models\Product\ProductLang {#615 ▶}
]
}
Thanks for any help..

There is a collection method called keyBy. Also, I woudn't use a conditional parameter in a relationship the way you pass $lang_id. I'd rather create two relationship methods.
So, you can do:
$products = Product::has('languages')
->paginate(20)
->getCollection()
->map(function ($product) {
return $product->languages->keyBy('lang_id');
});
return response()->json($products);

You could try and remap the key of the loaded relationship after the query like so:
$products = Product::has('languages')->paginate(20);
foreach($products as $product){
$product->setRelation('languages', $product->languages->mapWithKeys(function($language){
// Assuming the code is in the attribute `language_code`
return [$language->language_code => $language];
}));
}
return response()->json($products);

You can use mapWithKeys collection method.
As per Laravel Documentation:
The mapWithKeys method iterates through the collection and passes each
value to the given callback. The callback should return an associative
array containing a single key / value pair:
$keyed = $products->mapWithKeys(function ($item) {
return [$item['locale'] => $item]; // assuming 'locale' key
});
$keyed->all();
References:
Laravel -> Collections -> Method mapwithkeys
Laracast -> Change eloquent model relationship key

Related

get access to array build with pluck function in laravel

this is the query
$gg = DB::table('member_opinions')->where('user_id',$id)->pluck('committees_opinion');
result of dd($gg);
Illuminate\Support\Collection {#1436
#items: array:2 [
0 => "مؤهل"
1 => "غير مؤهل"
]
}
and I want to compare the values in loop in the controller
The each method iterates over the items in the collection and passes each item to a closure. Here you can compare the values.
$gg->each(function ($item, $key) {
//
});
More collections method is also present. Link for ref - https://laravel.com/docs/8.x/collections

Property [id] does not exist on this collection instance in laravel

store a query in array and call the result in view page show Property [id] does not exist on this collection
in controller
foreach($carvalue as $row){
$products[]=DB::table('products')->where('id',$row['product_id'] )->get();
}
and pass the products variable to view page and print the value like
foreach($products as $prod){
if($prod->id==$rows['product_id']){
//code
}
}
show the error and i dd($produts) the result is
array:2 [▼
0 => Illuminate\Support\Collection {#491 ▼
#items: array:1 [▼
0 => {#503 ▼
+"id": "130"
+"title": "Rfdfd"
+"sku": "vbff"
+"sub_title": "RC10 Matte Graphite"
}
]
}
1 => Illuminate\Support\Collection {#505 ▶}
]
why show this type error and how to solve it ?
In your query, replace get() with first()
$products[]=DB::table('products')->where('id',$row['product_id'] )->first();
OR
reference the first (and only) $products as $products[0], so it gets the id from the FIRST (and only, in your case) product
foreach($products[0] as $prod){
if($prod->id==$rows['product_id']){
//code
}
}

how to sum a collection after groupBy laravel

i have a collection named detailed as below :
Collection {#1421 ▼
#items: array:2 [▼
3943 => Collection {#1419 ▼
#items: array:2 [▼
0 => RoomPricingHistory {#923 ▶}
1 => RoomPricingHistory {#1042 ▶}
]
}
3944 => Collection {#1420 ▼
#items: array:2 [▼
0 => RoomPricingHistory {#1153 ▶}
1 => RoomPricingHistory {#1264 ▶}
]
}
]
}
now i want to get the sum of RoomPricingHistory for 3943 item and 3944 ofc it can be more of 2 item so i want to get the sum of each collection how can i achieve that ??
The Collection sum method can take a callback so you can define what is going to be calculated. In this case you can call sum on the main collection and in the callback which will give you access to the internal collections, also call sum.
$detailed->sum(function ($group) {
return $group->sum('sales_price');
});
Laravel 6.x Docs - Collections - Available Methods - sum
Since that isn't what you are looking for, you can use something like mapWithKeys to go through the collection and call sum for the groups to get the sum for each group:
$sums = $detailed->mapWithKeys(function ($group, $key) {
return [$key => $group->sum('sales_price')];
});
Laravel 6.x Docs - Collections - Available Methods - mapWithKeys

Merge 2 Collections or Arrays by Key

I'm trying my best to prevent from looping over a collection to get more data that I need for a data table. I need a way to combine these 2 collections or arrays.
I have 2 functions inside a model that calls an API that gives me an array of data that I convert into a collection.
Orders()
public function orders(){
$orders_array = $this->api()->request('orders.json');
return collect($orders_array);
}
Returns:
Collection {#274 ▼
#items: array:2 [▼
0 => {#282 ▼
+"id": 628602961977
}
1 => {#270 ▶}
order_meta()
public function order_meta($order_id){
$order_metafields_array = $this->api()->request('meta.json');
return collect($order_metafields_array);
}
Returns:
Collection
#items: [
+"name": "meta_data"
]
What I am wanting to do is inject the order_meta() into each order using the order ID.
I guess I am wanting to do something like this:
public function orders_detailed(){
$orders = $this->orders();
$keyed = $orders->mapWithKeys(function ($item) {
return [$item['meta'] => $this->order_metafields($item['id'])];
});
}
In hopes it will return:
Collection {#274 ▼
#items: array:2 [▼
0 => {#282 ▼
+"id": 628602961977
+meta => {
+"name":"meta_data"
}
}
1 => {#270 ▶}
Is something like this possible? I'm also open to merging it in as an array first, then creating a collection.

Manually add item to existing object [Laravel 5]

Here is what I try to do:
$q = Question::where('id',$id -> id)->get();
$q[] = $q->push([ 'test' => true]);
dd($q);
This will output:
Collection {#220 ▼
#items: array:3 [▼
0 => Question {#225 ▶}
1 => array:1 [▼
"test" => true
]
2 => null
]
}
So 'test' => true will append as a new key, but I want to insert it in Question so latter I can access to it like this with foreach $q -> test
So here is how I want access to item:
#foreach($q as $qq)
{{ $qq->test }}
#endforeach
It can be done by using setAttribute() function of Eloquent Model (https://github.com/illuminate/database/blob/master/Eloquent/Model.php).
As You can see it stores data in protected $attributes using setAttribute(), and when we do $SomeModel->some_field it uses magic method __get() to retrieve item by association from attributes array.
Here is the resolution to Your question:
$Question = Question::find($id);
$Question->setAttribute('test', 'blablabla');
Apart from setAttribute(), you can use put() refer to this post for one item. And map() for many items, refer to this post.

Categories