Navigating through api response in php - php

I am trying to to pull data from an API response. but can't seem to figure out how to navigate to the "statistics" section of the response.
Here is the responce in short
{
"response": [
{
"player": {
},
"statistics": [
{
"team": {
"id": 49,
"name": "Chelsea",
"logo": "some data"
}
}
]
}
]
}
The code I have at the moment is as follows:
$leaguelist = array();
if (! empty( $desc-> response)) {
foreach ($desc->response as $players){
$player['id'] = $players->player->id;
$player['name'] = $players->player->name;
$player['first_name'] = $players->player->firstname;
$player['last_name'] = $players->player->lastname;
$player['age'] = $players->player->age;
$player['dob'] = $players->player->birth->date;
$player['pob'] = $players->player->birth->place;
$player['cob'] = $players->player->birth->country;
$player['nationality'] = $players->player->nationality;
$player['height'] = $players->player->height;
$player['weight'] = $players->player->weight;
$player['photo'] = $players->player->photo;
$player['team_logo'] = $players->statistics->team->logo;
$leaguelist[] = $player;
}
}
I am able to pull and display all data from the player directory just having problems working out the code to get onto the statistics
I have tried
$player['team_logo'] = $players->statistics->team->logo;
I can't really research much into this as I don't know what "this" is called, any help would be great as i am a hobbyist and have ran out of ideas.
Thank you in advance

Assuming that the response you show is in JSON, and you've then parsed it with json_decode, there are only two types of structure you need to know about:
Anything in [] square brackets is an array, and is accessed as numbered items [0], [1], etc; or with a foreach loop
Anything in {} curly brackets is an object, and is accessed using ->foo, etc
So working from the outside, we have:
An outer object { which you've called $desc
... from which we want key "response": $desc->response ...
Then an array [, which you've looped over: foreach ($desc->response as $players)
Then in the first item of that array, an object { which the loop assigns to $players ...
... from which we want key "statistics": $players->statistics ...
Then an array [ ...
... from which we could take the first item: $stat = $players->statistics[0]; or loop over all the items: foreach ( $players->statistics as $stat )
Each item is then an object { ...
... from which we want the "team" key: $stat->team
Which is an object { ...
... from which we want the "id" key: $stat->team->id
If we just wanted that one value, we could write it all in one go: $desc->response[0]->statistics[0]->team->id. It doesn't matter how deep we're nesting, we just need to look for the [ or { to see what to do next.

statistics is an array. So if you want an item from within it, you need to refer to an index of that array which contains the item.
E.g.
$player['team_logo'] = $players->statistics[0]->team->logo;
to get the first item.

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

Removing entire array elements if an element in a sub array already exists in another element

I have a multidimensional array, consisting of products. Each sub-array has a product type. The productType is is in an array inside the Product array, such that;
0 => product [
productType [
id: 2
]
]
1 => product [
productType [
id: 1
]
]
2 => product [
productType [
id: 2
]
]
]
I need to remove an entire array element, if the id already exists, in this example, I would need to remove EITHER array[0] or array[2], it doesn't matter as I only need the productType[id] to populate the box.
I have made a loop that creates an array of the ID's that already exist, but it involves making 2 new arrays:
//This works but seems a bit inefficient
$productFinal = [];
$ids = [];
foreach ($products as $product) {
if (!in_array($product->getproductType()->getid(), $ids)) {
$productFinal[] = $product;
}
$ids[] = $product->getproductType()->getid();
}
I get the results I want, however I am sure that there is a more efficient way to do this, ideally using an inbuilt php function.
If you also get the key of each element, you could remove the element if necessary inside the foreach-loop:
$ids = [];
foreach ($products as $key => $product {
$id = $product->getproductType()->getid();
if (in_array($id, $ids)) {
unset($product[$key];
} else {
$ids[] = $id;
}
}
There is no need for a loop, you can use array_column to make the array associative, which will remove any duplicates.
Then use array_values to make the array indexed again.
$arr = array_values(array_column($arr, Null, "id"));

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

Modify JSON Feed With php

I have a JSON Feed which is accessed by an api.
The json feed it returns is as below:
[
{
"isoDate":"2017-09-15T00:00:00.0000000",
"events":[
{
"id":"-7317",
"name":"Exhibition SKMU: The collection 2015-2017",
},
{
"id":"-91417",
"name":"Torget - a multi cultural meeting place in Geilo",
}
]
},
{
"isoDate":"2017-09-16T00:00:00.0000000",
"events":[
{
"id":"-7317",
"name":"Exhibition SKMU: The collection 2015-2017",
},
{
"id":"-91417",
"name":"Torget - a multi cultural meeting place in Geilo",
}
]
}
]
I need the isoDate to be listed with each event instead of individually.
e.g.
[
{
"events":[
{
"isoDate":"2017-09-15T00:00:00.0000000",
"id":"-7317",
"name":"Exhibition SKMU: The collection 2015-2017",
},
{
"isoDate":"2017-09-15T00:00:00.0000000",
"id":"-91417",
"name":"Torget - a multi cultural meeting place in Geilo",
}
]
},
{
"events":[
{
"isoDate":"2017-09-16T00:00:00.0000000",
"id":"-7317",
"name":"Exhibition SKMU: The collection 2015-2017",
},
{
"isoDate":"2017-09-16T00:00:00.0000000",
"id":"-91417",
"name":"Torget - a multi cultural meeting place in Geilo",
}
]
}
]
Can this be achieved with php? Basically fetch that feed from a url and then display it in my preferred format?
So this is what you have to do, to get back your desired format of the json,
$json is your json string:
$eventList = json_decode($json);
foreach($eventList as $eventEntry){
$isoDate = $eventEntry->isoDate;
foreach($eventEntry->events as $subEventEntry){
$subEventEntry->isoDate = $isoDate;
}
//delete the isoDate from outer
unset($eventEntry->isoDate);
}
echo json_encode($eventList);
So basically, you are first decoding your json into php structure, apply your changes and after that, encode it back. Note here, that I have not appened true as second parameter for the $json_decode, but working with the resulting object.
Also: Your json is not standard comform and could result in errors. PHP will properly not decode it, because your object end with a comma. The last element of an object should be without comma. Instead of
{
"id":"-91417",
"name":"Torget - a multi cultural meeting place in Geilo",
}
make it like this:
{
"id":"-91417",
"name":"Torget - a multi cultural meeting place in Geilo"
}
I know, this can be a problem, when you get it from an API, but this is another problem of itself...
EDIT:
To get every "events" into one big array, you have to store them just like your imagination ;) . Think it like this: $subEventEntry holds one "events"-object. Because you are iterating both levels, you see everyone object of them. My suggestion would be to store them in a new array, and recreating the structure around it:
$everything = new stdClass();
$everything->events = array();
and then, in the inner loop:
foreach($eventList as $eventEntry){
$isoDate = $eventEntry->isoDate;
foreach($eventEntry->events as $subEventEntry){
$subEventEntry->isoDate = $isoDate;
$everything->events[] = $subEventEntry; // <-- this has to be added
}
//delete the isoDate from outer
unset($eventEntry->isoDate);
}
When recreating the structure, and you don't need the old structure anymore you could remove the unset.
Just remeber every [ ] pair in the json represents an array, every { } pair an object (stdClass). The name of this object/array is referenced -> by its class property in the superobject.
Yes you can using json_decode() function for example:
$yourjson;/* your json */
$events = json_decode($yourjson, true);
foreach($events as $event){
echo $event["isoDate"];
}
You can use json_decode to decode the json object to php array then modify the array and encode it using json_encode

How to access items within a collection map without breaking a fluent chain?

If you have a simple map using the Laravel collection, you can easily access the base collection by doing the following:
$items = [ "dog", "cat", "unicorn" ];
collect($items)->map(function($item) use ($items) {
d($items); // Correctly outputs $items array
});
If using a fluent chain with filters / rejections, $items no longer represents the set of items:
$items = [ "dog", "cat", "unicorn" ];
collect($items)
->reject(function($item) {
// Reject cats, because they are most likely evil
return $item == 'cat';
})->map(function($item) use ($items) {
// Incorrectly (and obviously) outputs $items array (including "cat");
// Would like to see the $items (['dog', 'unicorn']) here
d($items);
// Will correctly dump 'dog' on iteration 0, and
// will correctly dump 'unicorn' on iteration 1
d($item);
});
Question
Is it possible to access either the modified items array, or alternatively, get access to the collection in its current state.
Similar libraries in Javascript, like lodash, pass in the collection as the third argument - the Laravel collection does not.
Update/Edit
To be clear, I can do something like (but it breaks the chain). I would like to do the following, but without the inbetween storage of the collection.
$items = [ "dog", "cat", "unicorn" ];
$items = collect($items)
->reject(function($item) {
// Reject cats, because they are most likely evil
return $item == 'cat';
});
$items->map(function($item) use ($items) {
// This will work (because I have reassigned
// the rejected sub collection to $items above)
d($items);
// Will correctly dump 'dog' on iteration 0, and
// will correctly dump 'unicorn' on iteration 1
d($item);
});
When you do d($items); inside map() it refers to your original array. If you do var_dump($item) inside map() you'll see that it outputs only dog and unicorn.
$items = [ "dog", "cat", "unicorn" ];
$newItems = collect($items)
->reject(function($item) {
// Reject cats, because they are most likely evil
return $item == 'cat';
})->map(function($item) use ($items) {
var_dump( $item );//TODO
});
var_dump( $newItems );//TODO
You can access the current state of the collection by running something like $this->all().
$items = collect(["dog", "cat", "unicorn"])
->reject(function($item) {
return $item == 'cat';
})
->map(function($item) {
dd($item); // current item (dog/unicorn);
dd($this->all()); // all items in the collection (dog and unicorn);
});
you can do it something like this way.
return collect($models->items())->each(function ($item, $index){
if( !$item->quoteReturnDetail){ echo $item ; exit(); } });

Categories