converting a two dimensional javascript array to JSON - php

i've tried a few different json methods (stringify, toJSON, and probably some totally irrelevant others out of desperation) but can't seem to figure out how to stringify this so i can pass it to a php script. i am able to create a two dimensional array that which could be represented something like this:
array(
'image'=>array(
0=>'hello.jpeg',
1=>'goodbye.jpeg',
2=>'etc.jpeg'),
'resume'=>array(
0=>'resume.doc'),
'reel'=>array(
0=>'reel.mov')
)
the array looks okay when i print it to console using this dump function. i tried figuring out how to get this to work with objects because i thought i read something that said objects were already JSON friendly, but since i'm not super familiar with javascript i was pretty much floundering about.
edit: some more details... the declaration of my array (when i had it working) was something like this, although i may have messed up:
var fileArray = [];
fileArray['image'] = [];
fileArray['resume'] = [];
fileArray['reel'] = [];
var type;
var name;
var divs = $("#upload-container").children('div');
$.each(divs, function() {
type = $(this).attr('id');
name = $(this).html();
fileArray[type].push(name);
});

The object for that array structure might look like this in JavaScript:
var objects =
[
{
'image': [
{ '0': 'hello.jpeg' },
{ '1': 'goodbye.jpeg' },
{ '2': 'etc.jpeg' }
]
},
{
'resume': [
{ '0': 'resume.doc' }
]
},
{
'reel': [
{ '0': 'reel.mov' }
]
}
]
So now you've got an array of three objects, each of which contains a property (image, resume, reel) that is another array of objects with basically key:value pairs ('0':'hello.jpeg'). Maybe you could simplify it by not bothering to use the indexes:
var objects =
[
{
'image': [ 'hello.jpeg', 'goodbye.jpeg', 'etc.jpeg' ]
},
{
'resume': [ 'resume.doc' ],
},
{
'reel': [ 'reel.mov' ]
}
]
Then you can use JSON.stringify(objects) to pass to your PHP action.

Your sample expected output on the PHP side has an associative array containing numeric arrays. JavaScript arrays have numeric indexes: if you want strings as keys use a plain object rather than an array because JavaScript objects act like the associative arrays you are thinking of from PHP. The corresponding JavaScript object should look like this:
var fileArray = {
'image' : [ 'hello.jpeg',
'goodbye.jpeg',
'etc.jpeg'],
'resume' : [ 'resume.doc' ],
'reel' : [ 'reel.mov' ]
};
In the arrays defined with square brackets the numeric indexes are implied. Note that fileArray is defined with curly braces not square brackets and so is not an array (in spite of its name). This still allows you to use the fileArray['image'] = ... syntax if you want to set the properties one at a time:
var fileArray = {}; // an object, not an array
fileArray['image'] = [];
fileArray['resume'] = [];
fileArray['reel'] = [];
Note that the curly brackets in the initial declaration make it an object but properties are still accessed with square bracket syntax.
The way you were defining fileArray as a JavaScript array with square brackets still allows you to add string-based key properties because arrays are objects, but JSON stringify routines may ignore those properties and only serialise the numerically indexed properties.

Related

Extract particular array from multidimensional array

I have a JSON array of data that I am trying to extract particular value/keys(?) from, and would like to add them into a new array.
The array looks like this:
{ "total':2000,
"achievements":[
{
"id":6,
"achievement":{},
"criteria":{
"id":2050,
"is_completed":false
},
"completed_timestamp":1224053510000
},
{
"id":8,
"achievement":{},
"criteria":{
"id":1289,
"is_completed":true
},
"completed_timestamp":0000000
}
]
}
I want to search for true in the is_completed, and then add the id from that array into a new array.
Basically, find the id's of all the key/array (sorry unsure of terminology) where is_completed is true.
I've tried something simple like finding trying to find the key of an ID, but struggling to get that to work. And also seen some of the multi-level for loop examples but can't get them to work for my data.
Example:
$key = array_search('1289', array_column($array, 'id'));
As pointed out in the comments, you could combine array_filter (to filter completed events) and array_column (to extract their IDs).
$completedAchievements = array_filter(
$array->achievements,
static function (\stdClass $achievement): bool {
return $achievement->criteria->is_completed === true;
}
);
$completedAchievementsIds = array_column($completedAchievements, 'id');
print_r($completedAchievementsIds); // Array([0] => 8)
Note: the code above supposes your JSON was decoded as an object. If it was decoded as an array, just replace -> syntax with the corresponding array index access.
Demo

Array_map through a array of objects and grab properties

So I have a var_dump($instagram->get_images()); that gives me the following output:
I want to use array_map to map through all the properties and use them inside a foreach loop later on.. but I'm running into some issues:
Here is the attempt that I have:
$mediaUrls = array_map(function($entry) {
return [
'media_url' => $entry['media_url'],
];
}, $instagram->get_images());
I'm getting back the following error:
Could someone assist me on properly array_mapping through the objects and then later be able to use foreach ($MediaUrls as $media) etc...
The error is correct. You're using array map on an object. But the object does have a ->data property that is an array. But the items in the array are objects, so you'll need to refer to their properties rather than using array syntax.
$images = $instagram->get_images();
$mediaUrls = array_map(function($entry) {
return [
'media_url' => $entry->media_url,
];
}, $images->data);
Couple of suggestions. You said, "I want to use array_map to map through all the properties and use them inside a foreach loop later on."
You can reiterate $images->data later on, so I don't really see the value of making another array just for that purpose
foreach ($images->data as $imageData) {
// do something with $imageData->media_url
}
This would be almost exactly the same as iterating the array you're making with array_map.
foreach ($images->data as $imageData) {
// do something with $imageData['media_url']
}
If you want to get an array of just the urls, you can do it more simply with array_column.
$images = $instagram->get_images();
$mediaUrls = array_column($images->data, 'media_url');
(This won't give you the same result. It will be an array of strings rather than an array of arrays.)

How can I convert plain nested array to collection of entity objects?

I have a PHP plain array which I need converted to it's original entity. Example:
class Contact
{
protected $name;
getName(){}
setName(){}
}
This gets send back and forth via an API, and at some point I have that contact as an array element:
$example = ['name'=>'Foo Bar'];
I would like that back as an Contact class. At the moment, I can do that via a serialize/deserialize, but I'm hoping there is a more efficient method for this:
foreach($examples as $example) {
$temp = $this->serializer->serialize($example, 'json');
$contact = $this->serializer->deserialize($temp, Contact::class, 'json');
}
This works, and $contact is now instance of Contact. But I have to perform this on 100 items in one go, possibly more.
I'm thinking of creating a toObject() method, which assigns the values by keys, but that doesn't seem a lot better.
Is there way to accomplish this without writing my own logic or doing the extra serializing step?
Please note: I get the data array, I cant get the 'raw' json. Please take that 'as is'.
Denormalizing from raw JSON input
If you are getting the information from an API, you could probably do away with the JSON conversion and deal with the input directly, since most likely the API is not sending you a native array, but a JSON you are converting to an array at some point
The Serializer component can handle arrays as well, directly.
Assuming an input JSON like this:
$data = '[
{
"name": "Mary"
},
{
"name": "Jane",
},
{
"name": "Alice"
}
]';
You could call deserialize() saying you expect Contact[] in your input data:
$contacts = $serializer->deserialize($data, Contact::class . '[]', 'json');
This would get you a Contact array in one single step.
Denormalizing from array to object
If for some reason the original input is not available or not readily unserializable and you really need to convert from an array to an object one by one, and your objects have setters like the ones you show in your question; you could simply use the GetSetMethodNormalizer (one of the normalizers than the Serializer component uses internally).
E.g.:
$contacts = [
['name' => 'Mary'],
['name' => 'Jane'],
['name' => 'Alice'],
];
$normalizer = new GetSetMethodNormalizer();
foreach($contacts as $arrayContact){
$contact = $normalizer->denormalize(Contact::class, $arrayContact);
// do something with $contact;
}

adding object elements to array when they don't have keys=>values

I'm currently building an array off of an object and I've got one element called images that has multiple sub elements called 'urls' structured like so
categories": [
{
"images": [
{
"urls": [
"path/test.jpg",
"path/test2.jpg",
"path/test3.jpg"
],
},
{
"urls": [
"path/test4.jpg",
"path/test5.jpg",
"path/test6.jpg"
],
},
{
"urls": [
"path/test7.jpg",
"path/test8.jpg",
"path/test9.jpg"
],
},
]
The values there don't have keys, it's just the url path but I'd like to add these to my $groupItem array and just have each url be it's own element on the same level as the group number (basically I'm exporting and need each url as it's own column)
The structure I want
0 =>"path/test.jpg",
1 =>"path/test2.jpg",
2 =>"path/test3.jpg"
3 =>"path/test4.jpg",
4 =>"path/test5.jpg",
5 =>"path/test6.jpg"
6 =>"path/test7.jpg",
7 =>"path/test8.jpg",
8 =>"path/test9.jpg"
The loop/array:
foreach($prices->groups as $group){
$groupItem = array();
$groupItem["number"] = $group->number;
foreach($group->images as $images){
$groupItem["urls"] = $images->urls;
}
}
How can I simply just add on any url to the groupItem level of that array?
Outside the outer loop, init the value to an empty array:
$groupItem["urls"] = [];
Then use the empty array reference operator to append new values to the end of an array:
foreach($group->images as $images){
$groupItem["urls"][] = $images->urls; // add this url to the end of the list
}
Alternatively, use array_push():
foreach($group->images as $images){
array_push($groupItem["urls"], $images->urls);
}
I think you can probably also skip the inner loop and just use the array explode operator like this:
array_push($groupItem["urls"], ...$images->urls);
You might also use array_column with (from php 5.6) a variable length argument list:
For example, for the images which contains an array of objects where each object has a property urls and contains an array of image urls:
foreach ($prices->groups as $group) {
$groupItem = array();
$groupItem["number"] = $group->number;
$groupItem= array_merge($groupItem, ...array_column($group->images, "urls"));
}
Demo

Access JSON array values?

eSo I've got some parsed php data whiched I've fetched from my database and then parsed to JSON with json_encode(). Then I've used JSONparse() to make objects of my array. My code looks like this:
$.get("fetchDatabase.php", function(data){
var parsedData = jQuery.parseJSON(data);
}
I'm left with the array parsedData which looks like this:
[
{"person0":{"name":["Erik Steen"],"age":["1"]}},
{"person1":{"name":["Frida Larsson"],"age":["1"]}},
{"person2":{"name":["Abdi Sabrie"],"age":["2"]}},
{"person3":{"name":["Achraf Malak"],"age":["3"]}},
{"person4":{"name":["Adam Anclair"],"age":["1"]}}
]
I've placed those arrays in an array named
var peopleArray= { people: [ parsedData ] };
So far so good. Now what I want is being able to access certain persons attribute. Like names or age. How do I target those attributes? I've tried to print those attributes with no luck. I tried:
alert (peopleArray.people[0].person1.name);
Whiched returns:
Uncaught TypeError: Cannot read property 'name' of undefined
How can I access those attributes?
Apart from the typo ("namn") the problem is you're putting an array inside an array:
var peopleArray = { people: [ parsedData ] };
Since parsedData is an array then what you end up with is a structure like this:
// peopleArray
{ people : [ [ { "person0" : ... }, ... ] ] }
// oops -----^
See the problem? Since parsedData is a already an array the correct code would be:
var peopleArray = { people: parsedData };

Categories