Reading external JSON

If you have a PHP array, you can loop through it with a foreach loop

<?php
foreach($events as $event) {
  echo $event; // or if the event is an array, get an item by key
}

(don’t know what your array looks like)

Well its pretty big but it looks like this…ive anonymised some of the values

  object(Google_Service_Calendar_Events)#192 (19) {
  ["collection_key":protected]=>
  string(5) "items"
  ["accessRole"]=>
  string(6) "reader"
  ["defaultRemindersType":protected]=>
  string(37) "Google_Service_Calendar_EventReminder"
  ["defaultRemindersDataType":protected]=>
  string(5) "array"
  ["description"]=>
  string(24) "ANONYMOUS"
  ["etag"]=>
  string(18) ""p320dhkk6qidda0g""
  ["itemsType":protected]=>
  string(29) "Google_Service_Calendar_Event"
  ["itemsDataType":protected]=>
  string(5) "array"
  ["kind"]=>
  string(15) "calendar#events"
  ["nextPageToken"]=>
  NULL
  ["nextSyncToken"]=>
  string(28) "CIDY0obUmtUCEIDY0obUmtUCGAE="
  ["summary"]=>
  string(10) "ANOYMOUS"
  ["timeZone"]=>
  string(19) "America/Los_Angeles"
  ["updated"]=>
  string(24) "2017-07-21T15:09:36.000Z"
  ["internal_gapi_mappings":protected]=>
  array(0) {
  }
  ["modelData":protected]=>
  array(0) {
  }
  ["processed":protected]=>
  array(0) {
  }
  ["defaultReminders"]=>
  array(0) {
  }
  ["items"]=>
  array(1) {
  [0]=>
  object(Google_Service_Calendar_Event)#201 (57) {
   ["collection_key":protected]=>
   string(10) "recurrence"
   ["anyoneCanAddSelf"]=>
   NULL
   ["attachmentsType":protected]=>
   string(39) "Google_Service_Calendar_EventAttachment"
   ["attachmentsDataType":protected]=>
   string(5) "array"
   ["attendeesType":protected]=>
   string(37) "Google_Service_Calendar_EventAttendee"
   ["attendeesDataType":protected]=>
   string(5) "array"
   ["attendeesOmitted"]=>
   NULL
   ["colorId"]=>
   NULL
   ["created"]=>
   string(24) "2017-07-19T11:00:19.000Z"
   ["creatorType":protected]=>
   string(36) "Google_Service_Calendar_EventCreator"
   ["creatorDataType":protected]=>
   string(0) ""
   ["description"]=>
   NULL
   ["endType":protected]=>
   string(37) "Google_Service_Calendar_EventDateTime"
   ["endDataType":protected]=>
   string(0) ""
   ["endTimeUnspecified"]=>
   NULL
   ["etag"]=>
   string(18) ""3000925632264000""
   ["extendedPropertiesType":protected]=>
   string(47) "Google_Service_Calendar_EventExtendedProperties"
   ["extendedPropertiesDataType":protected]=>
   string(0) ""
   ["gadgetType":protected]=>
   string(35) "Google_Service_Calendar_EventGadget"
   ["gadgetDataType":protected]=>
   string(0) ""
   ["guestsCanInviteOthers"]=>
   NULL
   ["guestsCanModify"]=>
   NULL
   ["guestsCanSeeOtherGuests"]=>
   NULL
   ["hangoutLink"]=>
   NULL
   ["htmlLink"]=>
   string(116) "ANONYMOUS"
   ["iCalUID"]=>
   string(37) "ANONYMOUS"
   ["id"]=>
   string(26) "ANONYMOUS"
   ["kind"]=>
   string(14) "calendar#event"
   ["location"]=>
   string(40) "ANONYMOUS"
   ["locked"]=>
   NULL
   ["organizerType":protected]=>
   string(38) "Google_Service_Calendar_EventOrganizer"
   ["organizerDataType":protected]=>
   string(0) ""
   ["originalStartTimeType":protected]=>
   string(37) "Google_Service_Calendar_EventDateTime"
   ["originalStartTimeDataType":protected]=>
   string(0) ""
   ["privateCopy"]=>
   NULL
   ["recurrence"]=>
   NULL
   ["recurringEventId"]=>
   NULL
   ["remindersType":protected]=>
   string(38) "Google_Service_Calendar_EventReminders"
   ["remindersDataType":protected]=>
   string(0) ""
   ["sequence"]=>
   int(1)
   ["sourceType":protected]=>
   string(35) "Google_Service_Calendar_EventSource"
   ["sourceDataType":protected]=>
   string(0) ""
   ["startType":protected]=>
   string(37) "Google_Service_Calendar_EventDateTime"
   ["startDataType":protected]=>
   string(0) ""
   ["status"]=>
   string(9) "confirmed"
   ["summary"]=>
   string(17) "Google Event"
   ["transparency"]=>
   string(11) "transparent"
   ["updated"]=>
   string(24) "2017-07-19T11:13:36.132Z"
   ["visibility"]=>
   NULL
   ["internal_gapi_mappings":protected]=>
   array(0) {
   }
   ["modelData":protected]=>
   array(0) {
   }
   ["processed":protected]=>
   array(0) {
   }
   ["creator"]=>
   object(Google_Service_Calendar_EventCreator)#191 (7) {
     ["displayName"]=>
     string(11) "ANONYMOUS"
     ["email"]=>
     string(31) "ANONYMOUS"
     ["id"]=>
     NULL
     ["self"]=>
     NULL
     ["internal_gapi_mappings":protected]=>
     array(0) {
     }
     ["modelData":protected]=>
     array(0) {
     }
     ["processed":protected]=>
     array(0) {
     }
   }
   ["organizer"]=>
   object(Google_Service_Calendar_EventOrganizer)#204 (7) {
     ["displayName"]=>
     string(10) "ANONYMOUS"
     ["email"]=>
     string(52) "ANONYMOUS"
     ["id"]=>
     NULL
     ["self"]=>
     bool(true)
     ["internal_gapi_mappings":protected]=>
     array(0) {
     }
     ["modelData":protected]=>
     array(0) {
     }
     ["processed":protected]=>
     array(0) {
     }
   }
   ["start"]=>
   object(Google_Service_Calendar_EventDateTime)#193 (6) {
     ["date"]=>
     string(10) "2017-07-20"
     ["dateTime"]=>
     NULL
     ["timeZone"]=>
     NULL
     ["internal_gapi_mappings":protected]=>
     array(0) {
     }
     ["modelData":protected]=>
     array(0) {
     }
     ["processed":protected]=>
     array(0) {
     }
   }
   ["end"]=>
   object(Google_Service_Calendar_EventDateTime)#205 (6) {
     ["date"]=>
     string(10) "2017-07-21"
     ["dateTime"]=>
     NULL
     ["timeZone"]=>
     NULL
     ["internal_gapi_mappings":protected]=>
     array(0) {
     }
     ["modelData":protected]=>
     array(0) {
     }
     ["processed":protected]=>
     array(0) {
     }
   }
   ["reminders"]=>
   object(Google_Service_Calendar_EventReminders)#198 (7) {
     ["collection_key":protected]=>
     string(9) "overrides"
     ["overridesType":protected]=>
     string(37) "Google_Service_Calendar_EventReminder"
     ["overridesDataType":protected]=>
     string(5) "array"
     ["useDefault"]=>
     bool(true)
     ["internal_gapi_mappings":protected]=>
     array(0) {
     }
     ["modelData":protected]=>
     array(0) {
     }
     ["processed":protected]=>
     array(0) {
     }
   }
  }
  }
  }

So basically i need to merge data from that array with my side bar nav that currently contains kirby articles and have the google calendar events fall into the list in chronological order as if they were articles in Kirby:

    <?php
    // loop through the years
    $months = $site->find("events")->children()->visible()->filterBy('startdate', '>', date('Y-m-d'))->groupBy('startdate');

    foreach($months as $month => $itemsPerMonth): ?>
        <?php $eventdate = $month; ?>
        <?php $eventmonth = date("F",strtotime($eventdate)); ?>
        <?php $eventday = date("j",strtotime($eventdate)); ?>

        <h4><?php echo $eventmonth ?></h4>

        <ul class="article-subnav">
          <?php foreach($itemsPerMonth as $item) : ?>
          <li><a href="<?php echo $item->url() ?>"><strong class="day"><?php echo $eventday ?></strong>
           <?php echo $item->title() ?></a>
          </li>
          <?php endforeach; ?>
        </ul>
    <?php endforeach ?>

Well, currently, you don’t have an array, but an object of type Google_Service_Calendar_Events. The documentation tells you, how and what you can get from it (for example, getItems()). Then dump the items to see what’s in there and so on.

Unfortunately, this is far beyond Kirby support. If you want to merge that with Kirby stuff, I think the best way is to try to get the information you need out of the API, then merge Kirby events and Google API events into some sort of array.

Sure, I appreciate it’s a bit out of Kirby support but thanks for the nudge. I asked originally because i thought there was probably some way built into to Kirby for reading the data.

Each API is different and like Kirby, each object has its methods to extract the data you need. The principle is always the same, like Kirby’s page or collection objects have their methods to manipulate the objects.

sadly i do not know about the google api.

wasn’t part of your question but if you ever need to create ics yourself i found this lib useful - if you set timezone correctly that is.

So im at the last hurdle. I now have an array with the merged events, but when i try to use filterBy to sort it by date order, i get an error:

My array looks like:

    array(3) {
    [0]=>
    array(4) {
    ["ETitle"]=>
    object(Field)#231 (3) {
    ["page"]=>
    string(19) "events/launch-party"
    ["key"]=>
    string(5) "title"
    ["value"]=>
    string(12) "Launch Party"
    }
    ["EStart"]=>
    string(19) "2017-07-26T09:00:00"
    ["EEnd"]=>
    string(19) "2017-04-28T17:00:00"
    ["ELink"]=>
    string(35) "http://example.dev/events/launch-party"
    }
    [1]=>
    array(4) {
    ["ETitle"]=>
    object(Field)#248 (3) {
    ["page"]=>
    string(15) "events/open-day"
    ["key"]=>
    string(5) "title"
    ["value"]=>
    string(8) "Open Day"
    }
    ["EStart"]=>
    string(19) "2017-08-10T00:00:00"
    ["EEnd"]=>
    string(19) "2017-08-11T00:00:00"
    ["ELink"]=>
    string(31) "http://example.dev/events/open-day"
    }
    [2]=>
    array(4) {
    ["ETitle"]=>
    string(17) "Test Google Event"
    ["EStart"]=>
    NULL
    ["EEnd"]=>
    NULL
    ["ELink"]=>
    string(116) "https://www.google.com/calendar/event?eid=NjdsZW9ydmE4bWlmOHRnZ3J0dGw3MTVlamIgcnY3YTZyMTlmMjQyMHZvcmFkcWNrbW1zdG9AZw"
    }
    }

But when i try to order it with:

  $allevents = array_merge($kcaleventlist, $gcaleventlist);
  $chronos = $allevents->filterBy('EStart', '>', date('Y-m-d'))->groupBy('EStart');
  var_dump($chronos);

I get the following message:

Call to a member function filterBy() on array

Do i need to turn the array into a collection or something? How would i do that?

Well, object methods like filterBy() (which is a method of the Kirby Collection class and the classes that inherit from it) can’t be used with arrays.

You can use PHP array filtering functions instead, for example http://php.net/manual/en/function.array-filter.php

That manual is your friend for all things PHP, anyway. So better bookmark it :wink:

Thanks :slight_smile: Ill bookmark the english version. Cant cope with learning German at the same time as PHP :slight_smile:

I’ve just noticed that the array has multi dimensions for the kirby articles. How do i flatten it out so that ive literally just got the page title for those? I’m creating the array of Kirby articles like this:

  $kirbyevents = $site->find("events")->children()->visible();

  $kcaleventlist = array ();

    foreach ($kirbyevents as $kcalendarData) {

    $kstartdate = $kcalendarData->startdate();
    $kstarttime = $kcalendarData->starttime();
    $kenddate = $kcalendarData->enddate();
    $kendtime = $kcalendarData->endtime();

    $kstartisoDate = date('Y-m-d\TH:i:s', strtotime("$kstartdate $kstarttime"));
    $kendisoDate = date('Y-m-d\TH:i:s', strtotime("$kenddate $kendtime"));

    $ktitle = $kcalendarData->title();

    $kcaleventlist[] = array('ETitle' => $ktitle, 'EStart' => $kstartisoDate, 'EEnd' => $kendisoDate, 'ELink' => $kcalendarData->url());

  } 

The result is this:

    [0]=>
    array(4) {
      ["ETitle"]=>
      object(Field)#231 (3) {
        ["page"]=>
        string(19) "events/launch-party"
        ["key"]=>
        string(5) "title"
        ["value"]=>
        string(12) "Launch Party"
      }
      ["EStart"]=>
      string(19) "2017-07-26T09:00:00"
      ["EEnd"]=>
      string(19) "2017-04-28T17:00:00"
      ["ELink"]=>
      string(35) "http://dama.dev/events/launch-party"
    }
    [1]=>
    array(4) {
      ["ETitle"]=>
      object(Field)#248 (3) {
        ["page"]=>
        string(15) "events/open-day"
        ["key"]=>
        string(5) "title"
        ["value"]=>
        string(8) "Open Day"
      }
      ["EStart"]=>
      string(19) "2017-08-10T00:00:00"
      ["EEnd"]=>
      string(19) "2017-08-11T00:00:00"
      ["ELink"]=>
      string(31) "http://example.dev/events/open-day"
    }
    }

But i was expecting this:

    array(1) {
      [0]=>
      array(4) {
      ["ETitle"]=>
      string(17) "Launch Event"
      ["EStart"]=>
      '2017-04-28T17:00:00'
      ["EEnd"]=>
      '2017-04-28T17:00:00'
      ["ELink"]=>
      string(116) "http://example.dev/events/launch-party"
      }
    }

Instead of passing the field object, just pass the value:

 $ktitle = $kcalendarData->title()->value();

@texnixe Thanks that was useful.

I have now solved this whole problem, after 3 days of swearing :slight_smile:

Now i’m cleaning it up a bit, i want to move all my raw PHP to snippet so that i can use it on multiple templates without duplication. How do i do this so that the variables are accessable to the template that i place the snippet in?

From the docks It looks like the true parameter is what I want but it had no effect:

<?php snippet('site-caldata', null, true); ?>

The rest of the page cannot see the variables set in that snippet. Is it possible to do this? Should i use a standard PHP require instead?

Here’s how: https://getkirby.com/docs/templates/snippets/#passing-variables-to-snippets

Setting the return parameter to true does not help in this context.

It might be useful to define all variables you need in the snippet itself, so that the snippet is an independent unit you can just include anywhere, otherwise you would have to define your variables in each template/controller.

Thanks, but its the other direction i need want to go. I don’t want to pass a variable TO the snippet, the variable is in the snippet with a value and I want to get its value outside of the snippet, but it throws an error.

It works with a php require statement at the top of the template but i wondered if there was a more Kirby way :slight_smile:

This works: <?php require_once 'site/snippets/site-caldata.php'; ?>

What does not work is this:

<?php snippet('site-caldata.php') ?>
<?php snippet('site-calendar', ['eventroot' => $kcaleventlist]) ?>

The $kcaleventlist variable defined and given a value in the first snippet. I wan’t to use its value on the second snippet, but it errors and tells me the variable is undefined.

Ok, I think then it’s better to require the snippet or maybe define the data in a plugin file so that it get’s loaded automatically. I don’t know what is in your snippet, so hard to tell. The snippet() helper does not help in this case.

The snippet is just a lot of raw php that loads Google’s php api library, fetches all events from Kirby into an array, and does the same with the remote google calendar data. I end up with 3 arrays, $kcaleventlist, $gcaleventlist and $combinedeventlist.

It’s these three variables I need to pick up on in multiple templates.

Theres no Kirby code in the snippet, its just all vanilla PHP.

EDIT: Actually thats not true, theres like 3 lines of Kirby code in the snippet.

I’d probably wrap that stuff in plugin functions that return the variables so you can easily call those or pass them into your site-calendar snippet.

I’ll look into that, as its something I will need on other websites. If it comes out ok ill release to the community as a plugin.

inside snippet:
you could encode the return value of the snippet as json.

when calling snippet:
then decode that string with asociative flag.

but that takes up cpu time and a plugin/global function will be faster.

Gosh, thanks @bnomei but i gave up on turning it into a plugin a year ago (beyond my PHP skills). If your up for the task feel free to take it over, theres a working repo up here on github. Id love to see it cleaned up and refactored into a plugin.