Parse JSON without relying on order - php

I have this JSON, I'm parsing. I can retrieve all the values of field_data in order in PHP, but I need to traverse and get the values I wan't by specifying the field name, without concern for order:
JSON
{
created_time: "2018-05-14T16:11:02+0000",
id: "555555555555",
field_data: [
{
name: "bedrooms_interested_in?",
values: [
"2"
]
},
{
name: "When_are_you_looking?",
values: [
"January 1s 2019"
]
},
{
name: "email",
values: [
"xxxx#domain.com"
]
},
{
name: "full_name",
values: [
"John Michael"
]
},
{
name: "phone_number",
values: [
"+15555555555"
]
}
]
}
PHP
This is grabbing the last 3 fields. I'm currently able to pull the fields_data in order like this, but how could I grab the value fields I want by specifying the name field I'm looking for?
$data = json_decode($response, true);
// var_dump($data);
file_put_contents('dump.txt', $response);
$lead_email = $data['field_data'][2]['values'][0];
$lead_fullname = $data['field_data'][3]['values'][0];
$lead_phone = $data['field_data'][4]['values'][0];

You can use array_column to re-index an array by a given column, which will give you easier and more reliable access to the data:
$data['field_data'] = array_column($data['field_data'], null, 'name');
This allows you to access fields by name instead of their numeric index, e.g.
echo $data['field_data']['email']['values'][0];
// xxxx#domain.com
See https://eval.in/1003874 for a full example
(Note, I added some quotes to your JSON property names, since they were missing in the question. I assume that's a formatting issue, since this wouldn't work at all otherwise)

Related

How can I Iterate through PHP multi-dimension array that has label -> value structure

New to PHP (from C#). I have an array ($metaarray), which if I json_encode() to the screen, it has this value:
[
{
"measure":"Walking","record":"steps","latestres":"6870","datet":"2022-08-31"
},{
"measure":"","record":"kilograms","latestres":"117","datet":"2022-09-12"
},{
"measure":"","record":"","latestres":null,"datet":"2022-09-12"
},{
"measure":"Walking","record":"steps","latestres":"6840","datet":"2022-09-12"
},{
"measure":"Bodyweight","record":"kilograms","latestres":"92","datet":"2022-09-12"
},{
"measure":"Benchpress","record":"kilograms","latestres":"90","datet":"2022-09-12"
}
]
Is there an easy way for me to iterate through the metaarray - or to easily reference a record - eg. I would normally do something like:
$latestres = $metaarray[0][2];
...which should be "6870" - however it doesn't return any result when I do that.
Is there a way I can easily reference a particular value (eg. first record, "latestres" or 3rd value) in the above array?
I don't know if this helps you, but $data[2] does not represent third item in an array, unless the array happens to be created linearly (called a list). In PHP, 2 is actually the key to a map (name/value pair). So unless there is actually a key with that index, you can't access it. You can see a demo of what I'm talking about here.
You can get around the feature/limitation by using one of the tricks from this answer: https://stackoverflow.com/a/24825397/231316
function getNthItemFromArray(array $array, int $idx)
{
return $array[array_keys($array)[$idx]];
}
Obviously you'd add some guards.
As everyone notes, you should really start with your data before the encode. However, assuming that for whatever you have a JSON string, you can tell the decoder to give you an associative array instead of an object. Putting that all together you could do something like:
$json = <<<EOT
[
{
"measure":"Walking","record":"steps","latestres":"6870","datet":"2022-08-31"
},{
"measure":"","record":"kilograms","latestres":"117","datet":"2022-09-12"
},{
"measure":"","record":"","latestres":null,"datet":"2022-09-12"
},{
"measure":"Walking","record":"steps","latestres":"6840","datet":"2022-09-12"
},{
"measure":"Bodyweight","record":"kilograms","latestres":"92","datet":"2022-09-12"
},{
"measure":"Benchpress","record":"kilograms","latestres":"90","datet":"2022-09-12"
}
]
EOT;
$decoded = json_decode($json, true);
echo getNthItemFromArray($decoded[0], 2);
function getNthItemFromArray(array $array, int $idx)
{
return $array[array_keys($array)[$idx]];
}
Demo here: https://3v4l.org/POdma

JSONPath: how to get empty string (or null) if path (field) not exist?

Incoming JSON:
[
{
"name": "Name1"
},
{
"name": "Name2"
},
{
"name": "Name3",
"surname": "Surname3"
}
]
If we use JSONPath like $[:].name, we will receive:
[
0: "Name1",
1: "Name2",
2: "Name3"
]
But if will use the same to get surname ($[:].surname), we will receive:
[
0: "Surname3"
]
Is this possible to get surname values with empty string (or nulls) to keep right indexes? E.g.
[
0: "",
1: "",
2: "Surname3"
]
P.S.: at the moment I'm using this library.
JSON Path doesn't support returning placeholder values like that. It's a query language for JSON documents, much like SQL is for relational databases. Could you imagine if a SQL query returned placeholder values for every record in a database that didn't match your query?
I expect that the reason you want this is to determine where in the original document the value appears. To that end, JSON Path implementations should support returning the paths to the values instead of the values themselves:
[
"$[2]['surname']"
]
But I can't see in the README of that library where such a feature is supported (though it still might).

How to prevent whereRaw from automatically sort my collection?

I have a list of ids which are id of a collection after sorted, e.g:
$orderedIds = "2,18,4,1,17,5,6,16,15,14,13,11,12,10,9,8,7,3"
and I want to pick them out with whereRaw like this:
$result = Collection::whereRaw("FIELD(id, ".$orderedIds." )");
but the result is automatically sorted by id, which means the collection output is literally the original collection:
[
{
"id": 1,
...
}, {
"id": 2,
...
}, {
"id": 3,
...
}
]
Any option with whereRaw, or any other way around for me to achieve the sorted collection?
Try this
Collection::whereIn('id',$orderedId)->orderByRaw(DB::raw("FIELD(id, $orderedId)"))->get();

Laravel Validator Facade - Validate size based on another field value

I have a form where the user must define the number of items to save and when you submit the form and parse it to JSON it looks like this:
{
"numItems": 3,
"items": [
"1" : {"A": "Foo", "B:"bar"},
"2" : {"A": "Foo", "B:"bar"},
"3" : {"A": "Foo", "B:"bar"},
],
}
And I want to validate that the number of items inside items matches with the value of numItems.
I've tried with:
$aValidations = [
"numItems" => "required|int|max:10",
"items" => "required|array|size:numItems",
]
But even if the number of item matches the numItems value I get this:
{
"message": "The given data was invalid.",
"errors": {
"items": ["The items must contain numItems items."]
}
}
How can I achieve this?
One way would be to write a custom validator (you can put this in your AppServiceProvider#boot method). Something like (not tested/pseudocode):
Validator::extend('coolValidatorName', function ($attribute, $value, $parameters, $validator) {
$data = $validator->getData();
return $data[$parameters[0]] == count($value)
});
https://laravel.com/docs/5.5/validation#custom-validation-rules
The size rule accepts a numeric value which it then compares against the size of the input[1], it does not accept a field reference.
If you would like to compare against the value taken from another field you will need to pass in that field value yourself, e.g:
$aValidations = [
"numItems" => "required|int|max:10",
"items" => "required|array|size:" . $data->get('numItems'),
]
note: assumption has been made that you have decoded your json and then created a collection.
e.g:
$json = '{"numItems":4,"items":[{"a":"foo","b":"bar"},{"a":"foo","b":"bar"},{"a":"foo","b":"bar"}]}';
$data = collect((array) json_decode($json));
$aValidations = [
"numItems" => "required|int|max:10",
"items" => "required|array|size:" . $data->get('numItems'),
];
[1] For a string it compares the number of characters, for an integer it compares the values as is, for an array it compares the count of top level elements and for a file it compares the file size.

Sending object via $.post

I have an object saved in the variable called items.
0: Object
name: "Jim"
age: "42"
1: Object
name: "Bill"
age: "50"
When trying to post
$.post("mypage.php", items, function(data)
I get an empty post variable in the php page, but this returns post variables
$.post("mypage.php", "name=jim", function(data)
What am I doing wrong?
Edit it is an array of objects so if I pass
$.post( "mypage", items[0], function( data) {
I get a results but
$.post( "mypage", items, function( data) {
print_r is empty
It looks like the object you're posting may be an array with this format:
items = [
{
name: "Jim",
age: "42"
},
{
name: "Bill",
age: "50"
}
]
The docs seem to indicate that you must pass a plain object. You probably want to post something with the format:
items = {
people: [
{
name: "Jim",
age: "42"
},
{
name: "Bill",
age: "50"
}
]
};
Then you should be able to access the data via $_POST['people'].
UPDATE
To be accurate, you can post your array just fine, it will generate this post Jim=&Bill=
Almost surely not what you want. However if you follow the syntax specified by jQuery.param, your array will be treated correctly. Should be and array of objects with name and value:
items = [
{
name: "Jim",
value: "42"
},
{
name: "Bill",
value: "50"
}
]
You are using a curious behaviour of jQuery. It's found in the $.param function, which is used behind the scenes to prepare an AJAX query from your data.
If you send an array, jQuery expects it to be an array of objects, each of which has two keys, name and value. You are obviously not providing data in that structure. Your script actually sends data that looks like this:
Jim=undefined&Bill=undefined
If you do print_r($_POST['Jim']); in PHP, you will get the string undefined.
You obviously don't want this. You need to send the array within an object.
{
people: [
{
name: 'Jim',
age: 42
},
{
name: 'Bill',
age: '50'
}
]
}
This way your data will be serialised as this:
people[0][name]=Jim&people[0][value]=42&people[1][name]=Bill&people[1][age]=50
If you do print_r($_POST['people']);, you will get a meaningful result.

Categories