Concatenating two arrays and sum with keys via Laravel Collection - laravel

I'm having a set of array in something like this format:
[
{"GA_1":"1","GA_2":null,"GA_3":null,"GA_4":null},
{"SA_1":null,"SA_2":"2","SA_3":null,"SA_4":null},
{"RA_1":"1","RA_2":null,"RA_3":null,"RA_4":null}
]
I'm storing this in my mysql text column in json_decoded format. I want to call all the eloquent models and merge these arrays with sum of the each keys on object. For example
1st row contains:
[
{"GA_1":"1","GA_2":null,"GA_3":null,"GA_4":null},
{"SA_1":null,"SA_2":"2","SA_3":null,"SA_4":null},
{"RA_1":"1","RA_2":null,"RA_3":null,"RA_4":null}
]
2nd row contains:
[
{"GA_1":null,"GA_2":"1","GA_3":"2","GA_4":null},
{"SA_1":"1","SA_2":null,"SA_3":"3","SA_4":null},
{"RA_1":null,"RA_2":"2","RA_3":null,"RA_4":"5"}
]
3rd row contains:
[
{"GA_1":"1","GA_2":null,"GA_3":null,"GA_4":null},
{"SA_1":null,"SA_2":"2","SA_3":null,"SA_4":null},
{"RA_1":"1","RA_2":null,"RA_3":null,"RA_4":null}
]
so my final output should be:
[
{"GA_1":"2","GA_2":"1","GA_3":"2","GA_4":null},
{"SA_1":"1","SA_2":"4","SA_3":null,"SA_4":null},
{"RA_1":"1","RA_2":"2","RA_3":null,"RA_4":"5"}
]
I'm stuck in how can I achieve this:
$games = Game::get();
$grid = [];
foreach ($games as $game) {
$grid[] = collect($game->grid_values);
}
dd(collect('$grid')->flatten());
I'm getting this output:
Any suggestions are welcome. Thanks.

Well I tried something like this:
$games = Game::get();
$d = collect($games)->map(function($item) {
return json_decode($item->grid_values);
})->flatten();
$x = collect([
[
'GA_1' => $d->sum('GA_1'),
'GA_2' => $d->sum('GA_2'),
'GA_3' => $d->sum('GA_3'),
'GA_4' => $d->sum('GA_4'),
'GA_5' => $d->sum('GA_5'),
'GA_6' => $d->sum('GA_6'),
'GA_7' => $d->sum('GA_7'),
'GA_8' => $d->sum('GA_8'),
'GA_9' => $d->sum('GA_9'),
'GA_0' => $d->sum('GA_0'),
],
[
'SA_1' => $d->sum('SA_1'),
'SA_2' => $d->sum('SA_2'),
'SA_3' => $d->sum('SA_3'),
'SA_4' => $d->sum('SA_4'),
'SA_5' => $d->sum('SA_5'),
'SA_6' => $d->sum('SA_6'),
'SA_7' => $d->sum('SA_7'),
'SA_8' => $d->sum('SA_8'),
'SA_9' => $d->sum('SA_9'),
'SA_0' => $d->sum('SA_0'),
],
[
'RA_1' => $d->sum('RA_1'),
'RA_2' => $d->sum('RA_2'),
'RA_3' => $d->sum('RA_3'),
'RA_4' => $d->sum('RA_4'),
'RA_5' => $d->sum('RA_5'),
'RA_6' => $d->sum('RA_6'),
'RA_7' => $d->sum('RA_7'),
'RA_8' => $d->sum('RA_8'),
'RA_9' => $d->sum('RA_9'),
'RA_0' => $d->sum('RA_0'),
],
]);
return response()->json(['data' => $x], 200);
And I got expected result, any improvisation please suggest.

Related

Laravel: How can I assertJson an array

I am creating a feature test for a Seminar. Everything is working great; I am trying to update my feature test to account for the seminar dates.
Each Seminar can have one or many dates, so I am saving these values as a json field:
// migration:
...
$table->json('dates');
...
Here is what my Seminar model looks like:
// Seminar.php
protected $casts = [
'dates' => 'array',
];
When saving the seminar, I am returning a json resource:
if ($seminar->save()) {
return response()->json(new SeminarResource($seminar), 200);
...
Using Postman, my Seminar looks a like this:
...
"capacity": 100,
"dates": [
"2020-10-15",
"2020-10-16"
],
...
So far so good!
In my test, I am testing that a seminar can be created.
$http->assertStatus(201)
->assertJson([
'type' => 'seminars',
'id' => (string)$response->id,
'attributes' => [
'dates' => $response->attributes->dates, // General error: 25 column index out of range
I've tried to convert the array to a string, or json_encode the value in the resource. I don't think that's the correct way since I am already casting the value as an array in the model.
How can I assert that my dates is returning an array?
+"dates": array:2 [
0 => "2020-10-15"
1 => "2020-10-16"
]
Thank you for your suggestions!
EDIT
When I dd($response->attributes->dates); this is what I'm getting (which is correct).
array:2 [
0 => "2020-10-15"
1 => "2020-10-16"
]
What I'm not sure is how to assert an array like that. Since I'm using faker to generate the date, I don't really know (or care) what the date is, just want to assert that it is in fact an array.
I've tried something like:
'dates' => ['*'],
However, that just adds another element to the array.
EDIT 2
If I make the array a string,
'dates' => json_encode($response->attributes->dates),
I'll get an error like this:
--- Expected
+++ Actual
## ##
- 'dates' => '["2020-10-15","2020-10-16"]',
+ 'dates' =>
+ array (
+ 0 => '2020-10-15',
+ 1 => '2020-10-16',
+ ),
In my database, the values are stored like this:
["2020-10-15","2020-10-16"]
My actual test looks like this:
$http->assertStatus(201)
->assertJsonStructure([
'type', 'id', 'attributes' => [
'name', 'venue', 'dates', 'description', 'created_at', 'updated_at',
],
])
->assertJson([
'type' => 'workshops',
'id' => (string)$response->id,
'attributes' => [
'name' => $response->attributes->name,
'venue' => $response->attributes->venue,
'dates' => $response->attributes->dates,
'description' => $response->attributes->description,
'created_at' => (string)$response->attributes->created_at,
'updated_at' => (string)$response->attributes->updated_at,
],
]);
$this->assertDatabaseHas('workshops', [
'id' => $response->id,
'name' => $response->attributes->name,
'venue' => $response->attributes->venue,
'dates' => $response->attributes->dates,
'description' => $response->attributes->description,
]);

How to access data from an array when it's inside an std object? Error: Illegal string offset 'id'

How to access this array object in Laravel 6, using Eloquent?
[line_items] => Array
(
[0] => stdClass Object
(
[id] => 4088662196333
[variant_id] => 29653605285997
$external = DB::table('orders')->pluck('import_order_data');
...
foreach ($external as $key => $val) {
...
Cart::updateOrCreate([
'line_item_id' => ['line_item_id' => $val['id']],
],
ErrorException
Illegal string offset 'id'
If I change it to:
'line_item_id' => ['line_item_id' => $val->id],
I get error:
ErrorException
Trying to get property 'id' of non-object
If I change it to:
'line_item_id' => ['line_item_id' => $val['line_items']->id],
I get error:
Illegal string offset 'line_items'
EDIT:
The problem was:
protected $casts = [
'import_order_data' => 'array',
];
Now I can access it like this:
dd($val['line_items'][0]['id']);
Which provides:
4092309209197
or
dd($val['line_items']);
which provides:
array:1 [▼
0 => array:26 [▼
"id" => 4092309209197
"sku" => "1605"
"name" => "Printer Ink"
Any better options on accessing the data?
EDIT:
Answer:
foreach ($val['line_items'] as $index => $lineItem) {
dd($lineItem['id']);
Which provides:
4092309209197
Is this a reasonable way to do it?
If I understand correctly, your array looks like this:
$arr = [
[
"id" => 4092309209197,
"sku" => "1605",
"name" => "Printer Ink",
....etc.....
]
];
Fine. First, since the outer array only has one item, you can do this:
$innerArr = $arr[0];
Now you've got this:
$innerArr = [
"id" => 4092309209197,
"sku" => "1605",
"name" => "Printer Ink",
....etc.....
]
And you can access it like this:
echo $innerArr["id"];
echo $innerArr["sku"];
....etc....
Or like this:
foreach($innerArr as $key => $val){
echo $key.": ".$val."\r\n";
}

Map array values to collection of items

How would one do the following elegantly with laravel collections ?
Map the values of the $baseMap as keys to the collection.
The baseMap :
$baseMap = [
'name' => 'new_name',
'year' => 'new_year',
];
The collection :
$items = collect([
[
'name' => 'name1',
'year' => '1000',
'not_in_basemap' => 'foo'
],
[
'name' => 'name2',
'year' => '2000',
'not_in_basemap' => 'foo'
],
//...
]);
The end result :
$result =[
[
'new_name' => 'name1',
'new_year' => '1000',
],
[
'new_name'=> 'name2',
'new_year' => '2000',
],
];
I know how to do it in plain php , just wondering what a nice collection version would be. Thanks!
I tried to find collection methods, or php functions, but without success. Some dirty code that works with different keys from both sides (items and basemap).
$result = $items->map(function($item) use ($baseMap) {
$array = [];
foreach($baseMap as $oldKey => $newKey){
if(isset($item[$oldKey])){
$array[$newKey] = $item[$oldKey];
}
}
return $array;
});
$result = $result->toArray();
Thanks to #vivek_23 and #IndianCoding for giving me idea's I ended up with the following :
I made a small edit to make sure the mapping and the items keys lined up.
so you don't have to worry of misalignment and all in laravel collection !
$baseMap = collect($baseMap)->sortKeys();
$result = $items->map(function ($item) use ($baseMap) {
return $baseMap->values()
->combine(
collect($item)->sortKeys()->intersectByKeys($baseMap)
)
->all();
});
Use intersectByKeys to filter your baseMap keys with $items values.
$result = $items->map(function($item,$key) use ($baseMap){
return array_combine(array_values($baseMap),collect($item)->intersectByKeys($baseMap)->all());
});
dd($result);
Update:
In a pure collection way,
$baseMapCollect = collect($baseMap);
$result = $items->map(function($item,$key) use ($baseMapCollect){
return $baseMapCollect->values()->combine(collect($item)->intersectByKeys($baseMapCollect->all())->values())->all();
});
dd($result);
Here are my two cents, using map. Don't know how dynamic your collection should be, but knowing the keys I would do the following:
$baseMap = [
'name' => 'new_name',
'year' => 'new_year',
];
$items = collect([
[
'name' => 'name1',
'year' => '1000',
'not_in_basemap' => 'foo'
],
[
'name' => 'name2',
'year' => '2000',
'not_in_basemap' => 'foo'
],
])->map(function($item, $key) use ($baseMap) {
return [
$baseMap['name'] => $item['name'],
$baseMap['year'] => $item['year']
];
});

How to mix $query->andFilterWhere and $query->query in Yii2 elasticsearch 6

I updated my yii2 system from yii2-elasticsearch 2.0 to 2.1 and elasticsearch package from 2.2.1 to 6.2.1. In the old system I could mix $query->andFilterWhere and $query->query as follows (the search method is in a class derived from yii\elasticsearch\ActiveRecord):
public function search($params)
{
$query = self::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
$query->andFilterWhere([
'languageCode' => \Yii::$app->locale->languageCode,
]);
$queryPart = [];
if (!empty($this->term)) {
$queryPart['filtered']['query']['multi_match'] = [
// ES6: $queryPart['bool']['must']['multi_match'] = [
'query' => $this->term,
'operator' => 'and',
'type' => $this->getQueryType($this->term),
'fields' => [
'name_*',
'meta_description_*'
]
];
}
if (!empty($queryPart)) {
$query->query($queryPart);
}
return $dataProvider;
}
It worked with ES 2.2.1 without any problem, but now the andFilterWhere overwrites $query->query independently from the sequence. If one of the two parts is removed the other filter works perfectly, only together not.
Any idea?
You must use bool query and put all part of your query in one "query" object...
Something like this:
query => [
bool => [
must => [
multi_match => [
'query' => $this->term,
'operator' => 'and',
'type' => $this->getQueryType($this->term),
'fields' => [
'name_*',
'meta_description_*'
]
]
]
filter => [
'languageCode' => \Yii::$app->locale->languageCode
]
]
]
This problem seems to be bug, as confirmed by other users on github.

How to save data in model using Yii2 grid with Editable column

Can anyone help on editable column in gridview.I am using Yii2 and stuck with it.
I can't save data in my model.I can post from gridview column.
In my grid view:
$gridColumns= [
'patient_no',
'category_name',
'sdv_text',
[
'class' => 'kartik\grid\EditableColumn',
'attribute'=>'sdv_status',
'pageSummary' => true,
'editableOptions'=> [
'header' => 'profile',
'format' => Editable::FORMAT_BUTTON,
'inputType' => Editable::INPUT_DROPDOWN_LIST,
'data'=> $StatusList,
]
],
// 'date_sdv_performed',
[
'class' => 'kartik\grid\EditableColumn',
'attribute'=>'date_sdv_performed',
'editableOptions' => [
'header' => 'Date Sdv Performed',
'inputType'=>\kartik\editable\Editable::INPUT_WIDGET,
'format'=>\kartik\datecontrol\DateControl::FORMAT_DATE,
'widgetClass'=> 'kartik\datecontrol\DateControl',
],
],
[
'class' => 'kartik\grid\EditableColumn',
'attribute'=>'comments',
'hAlign' => 'top',
'vAlign' => 'middle',
'width'=>'100px',
'headerOptions' => ['class' => 'kv-sticky-column'],
'contentOptions' => ['class' => 'kv-sticky-column'],
'pageSummary' => true,
],
];
GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'layout'=>"{items}\n{pager}",
'pjax'=>true,
'toolbar' => [
'{export}',
'{toggleData}'
],
'responsive'=>true,
'hover'=>true,
'columns' => $gridColumns
]);
In my controller action:
public function actionMonitoring($site_name)
{
$this->layout = 'sdv-carolina-main';
$Countries = new Countries;
$model = new Flagging;
$searchModel = new FlaggingSearch();
$dataProvider = $searchModel->monitoringsearch($site_name);
$allocatedsites = new AllocatedSites;
if (Yii::$app->request->post('hasEditable'))
{
$model = $this->findModel($model['flagging_id']);
$out = Json::encode(['output'=>'', 'message'=>'']);
$post = [];
$posted = current($_POST['Flagging']);
$post['Flagging'] = $posted;
if ($model->load($post)) {
$model->save();
$output = '';
if (isset($posted['sdv_status']))
{
$output = $model->sdv_status;
}
$out = Json::encode(['output'=>$output, 'message'=>'']);
}
echo $out;
return;
}
return $this->render('monitoring',
[
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'Countries' => $Countries,
'model'=>$model,
'allocatedsites' => $allocatedsites,
]);
}
The problem is I can't update my model because of I can't get the id.
I just need the id to update specific row.How can I get the id while using editable column?
Thanks in advance.
Actually the solution is easy. I just need the id of that specific row to update that.And in my ajax post I got something like this:
Flagging[0][status] NO
_csrf TlhyUm5kajAoNxgVNy0/ZCoyHApZUlNUFh0rB1gRPGoAFSIdGSAifQ==
editableIndex 0
editableKey 13
hasEditable 1
and found the editableKey is the id of that specific row!
Now in my controller I write down this code given below:
$_id=$_POST['editableKey'];
$model = $this->findModel($_id);
Here $_id is the posted editableKey value which is the id of the specific row.
and with the id I use it to get the specific model and just update data based on that id.

Resources