Transform nested collection in laravel - php

I have a nested collection that I want to transform, pulling some keys "up a level" and discarding some other keys.
Every item in the collection has an allergens property.
"allergens": [
{
"id": 2001,
"info": "Allergy advice",
"status": "does_contain",
"product_id": 71576,
"allergen_id": 1,
"allergen": {
"id": 1,
"name": "Celery"
}
},
{
"id": 2002,
"info": "Allergy advice",
"status": "may_contain",
"product_id": 71576,
"allergen_id": 11,
"allergen": {
"id": 11,
"name": "Peanuts"
}
}
],
I need to make each items allergens property, look like
"allergens": [
{
"id": 1,
"name": "Celery"
"status": "does_contain",
},
{
"id": 11,
"name": "Peanuts"
"status": "does_contain",
},
],
I've tried the following:
$collection = $collection->transform(function ($item, $key) {
$item->allergens = $item->allergens->map(function ($allergen) {
return [
'id' => $allergen->allergen->id,
'name' => $allergen->allergen->name,
'status' => $allergen->status,
];
});
return $item;
});
But it doesn't overwrite the allergens property

Since you're posting your collection as JSON, I reverse engineered what your actual collection would look like. Turns out, your transform() works fine as far as I can tell. Maybe that helps you to find differences between my and your collection which might lead you to your problem/solution:
$collection = collect([
(object)[
"allergens" => collect([
(object)[
"id" => 2001,
"info" => "Allergy advice",
"status" => "does_contain",
"product_id" => 71576,
"allergen_id" => 1,
"allergen" => (object)[
"id" => 1,
"name" => "Celery"
]
],
(object)[
"id" => 2002,
"info" => "Allergy advice",
"status" => "may_contain",
"product_id" => 71576,
"allergen_id" => 11,
"allergen" => (object)[
"id" => 11,
"name" => "Peanuts"
]
]
]),
]
]);
$collection = $collection->transform(function ($item, $key) {
$item->allergens = $item->allergens->map(function ($allergen) {
return [
'id' => $allergen->allergen->id,
'name' => $allergen->allergen->name,
'status' => $allergen->status,
];
});
return $item;
});
dd($collection);
Result:
Illuminate\Support\Collection {#1779 ▼
#items: array:1 [▼
0 => {#1791 ▼
+"allergens": Illuminate\Support\Collection {#1775 ▼
#items: array:2 [▼
0 => array:3 [▼
"id" => 1
"name" => "Celery"
"status" => "does_contain"
]
1 => array:3 [▼
"id" => 11
"name" => "Peanuts"
"status" => "may_contain"
]
]
}
}
]
}

Related

Laravel api foreach argument must be of type array|object, null given in

i am getting product data from API end.
there are two nested "data" in the incoming array.
i can list the products with foreach, but I can't reach a single element.
when I try a few methods, it returns errors like "array,object int". Where am I going wrong and how can I access its elements?
the method i'm trying now is this and i'm applying this process on the Laravel side.
{
"data": {
"data": [
{
"id": 101553,
"company_id": 730,
"category_id": 132288,
"brand_id": 39549,
"name": "Hh PRODUCT TEST",
"remote_category_id": "scarf",
"remote_brand_id": "bershka123",
"spu": "zb3940823904"
},
{
"id": 101554,
"company_id": 730,
"category_id": 132289,
"brand_id": 39549,
"name": "Hs PRODUCT TEST",
"remote_category_id": "scarf",
"remote_brand_id": "bershka123",
"spu": "zb3940823905"
}
],
"count": 175,
"search": {
"category_id": null,
"brand_id": null,
"company_id": null
},
"start": 0,
"length": 10
},
"error_code": 0,
"message": ""
}
Model:
public function getProducts($start =0, $length =10, $category_id =null, $brand_id=null, $spu=null, $name=null, $is_active=null, $id=null, $remote_brand_id = null, $remote_category_id=null)
{
$request = Http::withHeaders([
'Authorization' => 'Bearer '.$this->jwttoken,
'Content-Type' => 'application/json'
])->post($this->sandbox . 'products/search',[
"start" => $start,
"length" => $length,
"search" => [
"category_id" => $category_id,
"brand_id" => $brand_id,
"spu" => $spu,
"name" => $name,
"is_active" => $is_active,
"id" => $id,
"remote_brand_id" => $remote_brand_id,
"remote_category_id" => $remote_category_id
]
])->json();
return $request;
}
controller
$company_id = 100;
$products = (new Client($company_id))->getProducts();
foreach($products as $product){
foreach($product as $prd){
dump($prd);
}
}
Result:
0 => array:27 [
"id" => 101530
"company_id" => 730
"category_id" => 132047
"brand_id" => 39316
"name" => "Hs Test Shoe"
"remote_category_id" => "5a39b114f1ff6e42639e9e041cd002d6"
"remote_brand_id" => "617392d2b51dbba1a2e5561a3e4eefe7"
"spu" => "845504"
],
1 => array:36 [
"id" => 231303
"company_id" => 730
"product_id" => 101530
"supplier_id" => null
"remote_supplier_id" => null
"name" => "Hd Test Shoe"
"description" => "This is a test product."
"sku" => "2K4F9966WHITE42"
]
ErrorException :
foreach() argument must be of type array|object, int given
How do i get the correct loop format and elements?
You have to loop like this way
foreach($products["data"]["data"] as $product)
{
dump($product);
}

Flat/Merge Array of Arrays and primitve types

i have an Array like this:
[ [ "id": 1, "name": "Kategorie 1", "parent_id": null, [ "id": 2, "name": "Kategorie 1.1", "parent_id": 1, [ "id": 5, "name": "Kategorie 1.1.1", "parent_id": 2, [ "id": 11, "name": "Kategorie 1.1.1.1", "parent_id": 5, [] ], [ "id": 12, "name": "Kategorie 1.1.1.2", "parent_id": 5, [] ] , ........]
So this is a Category Hierachy like:
Category 1
Category 1.1
Category 1.2
Category 1.2.1
Category 1.2.1.1.
Category 2
Category 2.1.
Category 2.1.1.
Category 2.2
Category 2.3.
But the depth of the Categories is variable.
So is there a way to flat/merge the Array to:
[ [ "id": 1, "name": "Kategorie 1", "parent_id": null], [ "id": 2, "name": "Kategorie 1.1", "parent_id": 1], [ "id": 5, "name": "Kategorie 1.1.1", "parent_id": 2], [ "id": 11, "name": "Kategorie 1.1.1.1", "parent_id": 5], [ "id": 12, "name": "Kategorie 1.1.1.2", "parent_id": 5] ]
There you go:
<?php
$array = [
[
"id" => 1, "name" => "Kategorie 1", "parent_id" => null,
[
"id" => 2, "name" => "Kategorie 1.1", "parent_id" => 1,
[
"id" => 5, "name" => "Kategorie 1.1.1", "parent_id" => 2,
[
"id" => 11, "name" => "Kategorie 1.1.1.1", "parent_id" => 5, []
],
[
"id" => 12, "name" => "Kategorie 1.1.1.2", "parent_id" => 5, []
]
]
]
]
];
function flatMerge(array $array, array &$result = [])
{
$subResult = [];
foreach ($array as $key => $sub) {
if (is_array($sub)) {
flatMerge($sub, $result);
} else {
$subResult[$key] = $sub;
}
}
$result[] = $subResult;
return $result;
}
$result = flatMerge($array); // flat merge the array
var_dump($result);
$result = array_filter($result, static function (array $array) { // remove empty arrays
return !empty($array);
});
var_dump($result);
$result = array_values($result); // reset array keys
var_dump($result);
You can see the result of this code here: http://sandbox.onlinephpfunctions.com/code/b4eaddb4a52f5e9cf9a80644190e526613381c60
Supposing your array like this:
$arr = [
[
"id" => 1, "name" => "Kategorie 1", "parent_id" => null,
"children" => [
"id" => 2, "name" => "Kategorie 1.1", "parent_id" => 1,
"children" => [
"id" => 5, "name" => "Kategorie 1.1.1", "parent_id" => 2,
children => [
[ "id" => 11, "name" => "Kategorie 1.1.1.1", "parent_id" => 5, "children" => [] ],
[ "id" => 12, "name" => "Kategorie 1.1.1.2", "parent_id"=> 5, "children" => [] ]
]
]
]
]
];
The following function may work in your case, using recursion function:
function flatten(array $array) {
$branch = [];
foreach ($array as $item) {
$children = [];
if (isset($item["children"]) && is_array($item["children"])) {
$children = flatten($item["children"]);
unset($item["children"]);
}
$branch = array_merge($branch, [$item], $children);
}
return $branch;
}

Group rows of data by a column value and restructure into an associative multi-dimensionsl array

I am trying to change an indexed array of arrays into a new array structure. My data is as follows:
$arr = array(
array( "year" => 1921, "name" => "bob" ),
array( "year" => 1944, "name" => "steve" ),
array( "year" => 1944, "name" => "doug" ),
array( "year" => 1921, "name" => "jim" ),
);
I would like to recreate a new array thats groups them into the same year. The best I can come up with is designating the year as the key so any row that has that year gets added to that key, but it's not the output that I'm looking for. What I need is how it's listed below.
"data": [
{
"year":"1921",
"names": [
{ "name":"bob" }, { "name":"jim"}
]
},
{
"year":1944",
"names": [
{ "name":"steve" }, { "name":"doug "}
]
}
You don't need to pre-extract the unique years nor use conditions within nested loops. Just push the data into the result set using temporary first-level keys, then remove the temporary keys when finished looping.
This ensures unique years, but allows names to be duplicated.
Code: (Demo)
$arr = [
["year" => 1921, "name" => "bob"],
["year" => 1944, "name" => "steve"],
["year" => 1944, "name" => "doug"],
["year" => 1921, "name" => "jim"],
];
foreach ($arr as $item) {
$result[$item['year']]['year'] = $item['year'];
$result[$item['year']]['names'][] = ['name' => $item['name']];
}
echo json_encode(
['data' => array_values($result)],
JSON_PRETTY_PRINT // for better visualization
);
Output:
{
"data": [
{
"year": 1921,
"names": [
{
"name": "bob"
},
{
"name": "jim"
}
]
},
{
"year": 1944,
"names": [
{
"name": "steve"
},
{
"name": "doug"
}
]
}
]
}

How to get collections inside array in Laravel or PHP

I am passing below data through API in postman.
I want to access these values from collection inside array for Items.
{
"user":"abc",
"supplier":"xyz",
"pdate":"1",
"items":[
{
"product":"Apple",
"qty":"1",
"rate":"40",
"amount":"40"
},
{
"product":"Banana",
"qty":"6",
"rate":"4",
"amount":"24"
}
]
}
Do you mean that you want to conver the items into Collection? If that's the case, you can do:
$data = json_decode('{ "user":"abc", "supplier":"xyz", "pdate":"1", "items":[ { "product":"Apple", "qty":"1", "rate":"40", "amount":"40" }, { "product":"Banana", "qty":"6", "rate":"4", "amount":"24" } ] }', true, 512, JSON_THROW_ON_ERROR);
$items = collect($data['items']);
dd($items);
This will output:
Illuminate\Support\Collection {#1545
#items: array:2 [
0 => array:4 [
"product" => "Apple"
"qty" => "1"
"rate" => "40"
"amount" => "40"
]
1 => array:4 [
"product" => "Banana"
"qty" => "6"
"rate" => "4"
"amount" => "24"
]
]
}
Please note, I have just added and json_decoded the data, for the sake of the example, but just do this in your controller where the data is passed in.

How to format JSON object PHP

I am trying to create a POST to a REST API to create a new object. I cannot figure out how to properly format my JSON.
Here's the response from the GET of an existing object:
{
"name": "product 2 mem"
"type": "simple"
"categories": array:1 [▼
0 => {
"id": 75
}
]
"meta_data": array:1 [▼
"id": 3665
"key": "_yith_wcbm_product_meta"
"value": {
"id_badge": "2955"
}
}
]
}
Here is the POST I'm trying to create:
$data = [
'name' => 'product name',
'type' => 'simple',
'categories' => [
[
'id' => 75
],
'meta_data' => [
'_yith_wcbm_product_meta' => [
'id_badge' => '2955'
]
]
];
You got typo in you json data.
$response = '{
"id": 3665,
"key": "_yith_wcbm_product_meta",
"value": {
"id_badge": "2955"
}
}';
$array = json_decode($response,true);
$return = ['meta_data'=>['key'=>$array['key'],'value'=>$array['value']]];
echo json_encode($return);
I figured out how to format it:
'meta_data' => [
[
'key' => '_yith_wcbm_product_meta',
'value' => ['id_badge' => '2955']
]

Categories