How to build this Laravel Eloquent Query - php

I want to build a nested array from a simple table with Laravel Eloquent, but i couldn't.
So basically below is a snap shot of my table
and this is the array I want to build

You can use some methods from collection :
$result = $data->groupBy(['market_id', 'base_currency', 'currency_id'])
->map(function ($item) {
return $item->map(function ($item) {
return $item->map(function ($item) {
return $item->map(function ($item) {
return $item['currency_id'];
});
})->flatten();
})->sortKeys();
});
dd($result->toArray());
array:1 [
1 => array:2 [
1 => array:2 [
0 => 2
1 => 3
]
2 => array:2 [
0 => 1
1 => 2
]
]
]
Explanation
groupBy
The groupBy method groups the collection's items by a given key. Multiple grouping criteria may be passed as an array. Each array element will be applied to the corresponding level within a multi-dimensional array:
$data->groupBy(['market_id', 'base_currency', 'currency_id']);
map
The map method iterates through the collection and passes each value to the given callback.
->map(function ($item) {
return $item;
});
flatten
The flatten method flattens a multi-dimensional collection into a single dimension:
->flatten()
sortKeys
The sortKeys method sorts the collection by the keys of the underlying associative array:
->sortKeys()

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

Set key to difference key when get laravel relationship

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

Where year filter Laravel collection

I have a Laravel collection with a "created_at" attribute, and I want to filter by year, like in eloquent:
$model->whereYear()
But in a collection.
Thx!
#attributes: array:10 [
"id" => 720
"created_at" => "2019-05-15 08:24:00"
"updated_at" => "2019-05-15 08:24:00"
]
You can use the Collections method filter to only find those whose year matches your criteria:
$collection = Model::all();
$collection->filter(function ($value) {
return $value->created_at->year === 2019; // assuming, that your timestamp gets converted to a Carbon object.
});

Laravel - replace null with empty array when no relation is found

Is it possible to replace null with an empty array when no relation is found?
E.g. The customer has contacts and contracts but one of the contract has no web.
$customers = Customer::with('contacts', 'contracts.web')
->orderBy('company')->orderBy('prename')->get();
The result would be as following...
2 => array:21 [
"id" => 1
"contacts" => array:2 [
0 => array:12 [
"id" => 1
"customer_id" => 1
]
1 => array:12 [
"id" => 2
"customer_id" => 1
]
]
"contracts" => array:2 [
0 => array:9 [
"id" => 1
"customer_id" => 1
"web" => array:7 [
"id" => 1
"contract_id" => 1
]
]
1 => array:9 [
"id" => 2
"customer_id" => 1
"web" => null // should be replaced with []
]
]
]
As I read in the docs (Constraining Eager Loads), it's only possible to manipulate the query with constraining eager loads.
UPDATE
Contract class
class Contract extends Model
{
public function web()
{
return $this->hasOne(Web::class);
}
}
For further readers here's an explanation how to solve this kind of problem.
Laravel returns an empty array if no records are found on a hasMany relation. If a hasOne relation is implemented, null will be returned.
So if you need an array also if no record is found on a hasOne relation, you need to do the following.
class Contract extends Model
{
public function web()
{
return $this->hasOne(Web::class)
->withDefault(function () {
return new Web();
});
}
}
As implemented like this its not possible to just return an empty array. Why this isn't possible, check out this issue on Laravel GitHub Issue Tracker.
There is existing code that depends on the result of any Eloquent relationship to either be null, a Model instance, or a Collection of Model instances. However, the current functionality of the withDefault() method opens up the potential for returning an object that is not one of those three expected values.
If you return a new \stdClass; or an empty array, an empty instance of web is returned. To get an empty array just instanciate a new Object of the relation class. In my case new Web();.
Your relationship method should be the one handeling this since it's the first place you can fix this
I checked this so it returns an array when the variable is null.
public class Contracts{
public function web(){
$collection = $this->hasMany('App\Web');
return $collection ? $collection : [];
}
}

Loop through JSON Array and display results in table - Laravel 5.2

This question probably has been asked many times, but i cant get a solution.
I'm calling to a API like this:
public function getLeaderBoardArray($leaderBoardStats) {
$array = [];
$ex = $leaderBoardStats;
dd($ex);
return $array;
}
This is the result I get when I (DD) (Die-Dump it):
{#201 ▼
+"Start": 0
+"Count": 100
+"ResultCount": 100
+"Results": array:100 [▼
0 => {#199 ▼
+"Player": {#186 ▼
+"Gamertag": "Ferro2Clutch"
+"Xuid": null
}
+"Rank": 1
+"Score": {#195 ▶}
}
1 => {#188 ▶}
2 => {#200 ▶}
3 => {#203 ▶}
4 => {#206 ▶}
5 => {#209 ▶}
6 => {#212 ▶}
....... and so on till 100
How can a loop through this array and display Players Gamertag.
This i what I'm doing right now:
public function getLeaderBoardArray($leaderBoardStats) {
$array = [];
$array['Gamertag_1'] = $leaderBoardStats->Results[0]->Player->Gamertag;
$array['Csr_1'] = $leaderBoardStats->Results[0]->Score->Csr;
$array['Gamertag_2'] = $leaderBoardStats->Results[1]->Player->Gamertag;
$array['Csr_2'] = $leaderBoardStats->Results[1]->Score->Csr;
// and so on til 10....
return $array;
}
As you can see, this would be a pain to do till 100 for each leader-board.
Is there an easier method like somehow doing a for each loop?
You asked a very similar question yesterday and I'm going to give you a very similar answer today.
https://laravel.com/docs/5.2/collections
Use the map() Collection functionality to convert each item to a more digestable array.
$results = collect($leaderBoardStats->Results);
$gamers = $results->map(function($item, $key)
{
return [
'gamertag' => $item->Player->Gamertag,
'csr' => $item->Score->Csr,
]
});
This will give you an array that looks like ...
[
['gamertag' => "name", 'csr' => 11111],
['gamertag' => "name", 'csr' => 11111],
['gamertag' => "name", 'csr' => 11111],
['gamertag' => "name", 'csr' => 11111],
];
Then, in your view, you can do this to build a table.
#foreach ($gamers->all() as $gamer)
<tr>
<td>{{ $gamer['gamertag'] }}</td>
<td>{{ $gamer['csr'] }}</td>
</tr>
#endforeach
All it takes. Laravel Collections are probably one of the strongest aspects of the entire framework and are incredibly robust and well built. If you have an array-related question, chances are that documentation has a collection-related answer.
you can write a simple loop to iterate through your results. for example, I like using a foreach loop
$array = [];
foreach ($leaderBoardStats->Results as $stat) {
array[] = [
'gamer_tag' => $stat->Player->Gamertag,
'csr' => $stat->Score->Csr
];
}
return $array;
A better more advanced approach would be to map this so you don't have to create any extra arrays.
return array_map(function ($stat) {
return [
'gamer_tag' => $stat->Player->Gamertag,
'csr' => $stat->Score->Csr
];
}, $leaderBoardStats->Results);

Categories