json_decode() will turn the JSON into a multidimensional array, so properties can be accessed like e.g. $json["VCALENDAR"] (not with the -> notation). Also, the value of "VCALENDAR" is itself an array with only one element, so a particular "VEVENT" would be accessed like e.g. $json["VCALENDAR"][0]["VEVENT"]. You might iterate over the "VEVENT"s like so:
$json = json_decode(file_get_contents('json/events.json'), true);
foreach ($json["VCALENDAR"] as $vcalendar) {
foreach ($vcalendar["VEVENT"] as $vevent) {
echo $vevent["LOCATION"] . "\n";
}
}
(Ah just noticed you already figured out the notation issue…) :-)
The first thing to keep in mind is that you’re passing true as the second argument to json_decode(), which causes JSON objects to be returned as associative arrays instead of PHP objects.
So, if you’re trying to get the LOCATION properties, your foreach is going to need to look like this:
foreach($json['VCALENDAR'][0]['VEVENT'] as $data) {
echo $data['LOCATION'] . "\n";
}
Notice that VCALENDAR is an array (even though it only holds a single object in your example) so you need to use the index (0) to access the first element.
You can use PHP’s DateTime class to format the date:
$start = new DateTime($data['DTSTART']);
echo $start->format('j F Y');
The formatting codes to display the different parts of the date are here.
Likewise fretburner with your approach, I appreciate the two slightly different ways of doing things here, some great knowlegde, big thank you in advance.
After much googling… Though I’m wondering why, and when I would use one over the other? $data->example vs $data['example']
I did think → was the new way of doing things.
Would things be better as a PHP object, or they work the same, not much benefit?
Cool, working good thanks for reference.
So generally speaking, now I have the json data available to me in a php array I can now spit out and organise this data exactly the same as I would with any db query. Is that correct? Meaning - it doesn’t matter where the data comes from, once inside the php array, everything works the same?
My updated code:
$json = json_decode(file_get_contents('events.json'), true);
foreach($json['VCALENDAR'] as $vcalendar)
{
foreach($vcalendar['VEVENT'] as $vevent) {
$start = new DateTime($vevent['DTSTART']);
echo "<h3>" . $vevent['SUMMARY'] . "</h3><p>Location: "
. $vevent['LOCATION'] . "<br />When: " . $start->format('j F Y') . "</p>";
}
}
Also wondering how we could add a sort() into the mix?
Preferable sort by the date NOW onwards excluding past dates.
Update: When I print $vevent['DESCRIPTION '] all the data is full of \ and \n randomly added within the copy. Why is this? Is there a way to remove it?
Some people prefer to access the data as an object rather than an associative array (i.e $vevent->SUMMARY rather than $vevent['SUMMARY']) but on the other hand this might prevent you from using some of PHP’s built-in array sorting/manipulation functions (depending on what you’re trying to do).
Yup, it’s just a normal collection of nested arrays at this point. You don’t need to worry about where the data came from.
I’d start by filtering the collection to include only the events that you want, using array_filter(). This takes an array and a filter function, and loops over the array, passing each element to the function. If the filter function returns true then that element is included in a new array which is returned by array_filter.
$today = new DateTime();
$current_events = array_filter($vcalendar['VEVENT'], function($event, $key) use ($today) {
$event_start = new DateTime($vevent['DTSTART']);
return $event_start >= $today;
}, ARRAY_FILTER_USE_BOTH);
Then I’d sort the resulting array, using usort. Note that this function doesn’t return a new array, it just sorts the array that you pass in as the first argument by passing pairs of elements to a sorting function that you pass as the second argument. This function should return 0 if the elements are equivalent, -1 if the first element comes before the second, and 1 if the first element should come after the second.
usort($current_events, function($a, $b) {
$date_a = new DateTime($a['DTSTART']);
$date_b = new DateTime($b['DTSTART']);
if ($date_a == $date_b) return 0;
return $date_a < $date_b ? -1 : 1;
});
I’ve managed to import the JSON data into MYSQL which is making things a little easier right now to select and organize the data… This has taken up all the time past couple of nights
The good thing is… we now have options and more power to query the data by using JSON or by importing the JSON into MYSQL which will become very handy for different projects.
Will post back very soon to discuss things further about the above.
Ok, I’ve decided to work with the mysql result which has turned out a little easier as mentioned. What you have suggested above is exactly what I need for my new snippet @fretburner VCALENDAR and VEVENT are no longer in use.
Just wondering how we can fit the ARRAY_FILTER and SORT into the new snippet below. Not sure if I need to create a new DateTime now - I have the row already formatted as shown below.
ORDER BY will be removed (somebody said PHP sorting is faster than SQL) is that correct?
$queryEvents = "
SELECT ID
, DTEND
, DTSTAMP
, LOCATION
, DTSTART
, SUMMARY
FROM events_test
ORDER BY DTSTART ASC";
$resultEvents = $mysqli->query($queryEvents);
$row_cnt = $resultEvents->num_rows;
$eventsArray = array();
/* fetch associative array */
while ($row = $resultEvents->fetch_assoc()) {
$row['endTime'] = date('g:ia', strtotime($row['DTEND']));
$row['fullDate'] = date('l jS F Y', strtotime($row['DTSTART']));
$row['startTime'] = date('g:ia', strtotime($row['DTSTART']));
$eventsArray[] = $row;
}
I’ll also be looking for a way to group these events into separate lists grouped under a date title, if maybe we could include this with the update somehow.
I came across array_chunk() though after further searching it seems a double foreach inside one another could be the right solution?
Before I create a new thread with the same problem, if anybody could help with the above much appreciated. I realise this has become slightly off topic thanks.
I have tried the below though returning array(0). And not sure how to fit this into the foreach.
$today = new DateTime();
$current_events = array_filter($eventsArray, function($event) use ($today) {
$event_start = $row['startTime'];
return $event_start >= $today;
});
var_dump($current_events);