$fluidbook_id = intval($fluidbook_id);
if ($fluidbook_id < 21210) {
- $server = 'stats3.fluidbook.com';
+ return 'stats3.fluidbook.com';
} elseif ($fluidbook_id % 2 === 0) {
- $server = 'stats4.fluidbook.com';
- } else {
- $server = 'stats5.fluidbook.com';
+ return 'stats4.fluidbook.com';
}
-
- return $server;
+ return 'stats5.fluidbook.com';
}
protected function getMatomoToken($server) : bool|string {
return $date_matches;
}
+ // Since the report date can be in different formats (ie. YYYY, YYYY-MM or a full range)
+ // and this format determines the report mode (range, month or year), we have to figure out
+ // the mode and full starting and ending dates, as necessary
+ public function getReportSettings($date, $fluidbook) {
+ $date_matches = $this->parseDate($date);
+
+ // ...
+
+ // TODO: centralise all mode + start / end date logic here... then in the main report function, we can use the returned mode in a switch() statement to clean things up a lot.
+
+
+ }
+
// Figure out the best period to use for the stats according to the date range
public function determinePeriod($dates, $fluidbook) {
+ // TODO: refactor this into getReportSettings() so that this function can simply take the determined start and end dates, calculate the number of days and give an answer based on that. No extra logic to try to figure out which mode it is...
+
// If no valid date range is given, use the Fluidbook's lifetime
if (empty($dates) || !is_array($dates)) {
$dates['start_date'] = $fluidbook->created_at->isoFormat('YYYY-MM-DD');
$locale = app()->getLocale();
$base_URL = route('stats', compact('fluidbook_id', 'hash')); // Used by date range picker to update report URL
+ // If the Fluidbook ID + hash combination isn't found, a 404 response will be returned
$fluidbook = FluidbookPublication::where('id', $fluidbook_id)->where('hash', $hash)->firstOrFail();
$fluidbook_settings = json_decode($fluidbook->settings);
$start_date = $dates['start_date'];
$end_date = $dates['end_date'];
$date_range = "{$start_date},{$end_date}";
- $formatted_date_range = Carbon::parse($start_date)->isoFormat('MMMM Do, YYYY') . ' — ' .
- Carbon::parse($end_date)->isoFormat('MMMM Do, YYYY');
+ // $formatted_date_range = Carbon::parse($start_date)->isoFormat('MMMM Do, YYYY') . ' — ' .
+ // Carbon::parse($end_date)->isoFormat('MMMM Do, YYYY');
// Human-friendly representation of the time span
// Since our start and end dates are only in the format YYYY-MM-DD, the time defaults to midnight
// calculates until the *start* of the end_date, effectively excluding it. To get a clean result,
// we add 1 day to the end date (setting time to 23:59:59 has undesired effects with the diff display)
$report_timespan = Carbon::parse($start_date)->startOfDay()->diffForHumans(Carbon::parse($end_date)->addDay(), [
- 'syntax' => CarbonInterface::DIFF_ABSOLUTE,
- 'parts' => 3, // How much detail to go into (ie. years, months, days)
+ 'syntax' => CarbonInterface::DIFF_ABSOLUTE, // Absolute means without "ago" added
+ 'parts' => 3, // How many levels of detail to go into (ie. years, months, days, hours, etc)
'join' => true, // Join string with natural language separators for the locale
]);
$date_range = "{$start_date},{$year}-{$month}-{$last_day_of_month}";
$end_date = ($month == date('m') && $year == date('Y')) ? date('Y-m-d') : "{$year}-{$month}-{$last_day_of_month}";
$chart_heading .= '<span class="heading-subtitle">' . Carbon::parse($start_date)->isoFormat('MMMM YYYY') . '</span>';
- $formatted_date_range = Carbon::parse($start_date)->isoFormat('Do') . ' — ' .
- Carbon::parse($end_date)->isoFormat('Do MMMM, YYYY');
} elseif (!empty($dates['start_year'])) { // Year view
$mode = 'year';
$start_date = "{$year}-01-01";
$date_range = "{$start_date},{$year}-12-31"; // Full range of specified year (guarantees a full chart, even if it's early in the current year)
$end_date = $year == date('Y') ? date('Y-m-d') : "{$year}-12-31"; // If it's the current year, don't count future dates
- $formatted_date_range = Carbon::parse($start_date)->isoFormat('MMMM Do, YYYY') . ' — ' .
- Carbon::parse($end_date)->isoFormat('MMMM Do, YYYY');
$chart_heading .= "<span class='heading-subtitle'>$year</span>";
} else { // No valid dates specified, display the full data set
$mode = 'overview';
$start_date = $fluidbook->created_at->isoFormat('YYYY-MM-DD');
$end_date = now()->isoFormat('YYYY-MM-DD');
-
- // If the Fluidbook is recent, the range will be very short (eg. just a few days or a month), which makes the
- // bar chart look strange due to lack of entries. There's no easy way to limit the width of the bar chart while
- // retaining the responsiveness, so instead we fetch a longer period of stats, even if they'll be mostly empty.
- if ($period === 'month' && $fluidbook->created_at->diffInMonths($end_date) < 12) { // For the overview, we want at least 12 months
- //$date_range = 'last12'; // Special date that Matomo understands
- // Originally this used the special "last12" setting that Matomo understands but this causes problems
- // later when we need to fetch certain statistics with a period of "range" - real dates are needed.
- // To make sure the populated bar graph data is at the left of the chart instead of the right,
- // we fetch future dates (Matomo just returns empty values in this case)
- // TODO: see if there's a more elegant solution to this, possibly in Chart.js
- $end_date = $fluidbook->created_at->addMonths(12)->isoFormat('YYYY-MM-DD');
- }
-
$date_range = "{$start_date},{$end_date}"; // All data up until today's date
- $formatted_date_range = $fluidbook->created_at->isoFormat('MMMM Do, YYYY') . ' — ' .
- Carbon::now()->isoFormat('MMMM Do, YYYY');
$chart_heading = __('Overview');
}
+ $formatted_date_range = $this->formatDateRange($start_date, $end_date);
+
//=== Set up Matomo Reporting API
$report = $this->getReporting($fluidbook_id);
$report->setDate($date_range);
$report->setPeriod($period);
+ $report->setLanguage($locale); // Matomo will return translated data when relevant (eg. country names)
// * Note about visits and page views:
// Although Matomo records visits and page views (API: VisitsSummary.get & Actions.get), we don't use these
$period_details = $pagesByPeriod->filter(fn ($value, $key) => !empty($value)); // Remove any empty periods
//=== CHART PREPARATION
- // Format dates for display as labels on the x-axis
- $labels = $pagesByPeriod->keys()->map(function ($label, $index) use ($period, $start_date, $end_date) {
- return $this->formatDateForXAxis($label, $period, $start_date, $end_date);
+ // Format dates for display as labels on the x-axis and in the tooltips / tables
+ $tooltip_labels = $pagesByPeriod->keys()->mapWithKeys(function($date, $index) use ($period, $start_date, $end_date) {
+ $short_label = $this->formatDateForXAxis($date, $period, $start_date, $end_date);
+ $full_label = $this->formatDateForPeriod($date, $period);
+ return [$short_label => $full_label];
})->toArray();
- // Format dates for display in the tooltip title
- $formatted_dates = $pagesByPeriod->keys()->map(function ($label, $index) use ($period) {
- return $this->formatDateForPeriod($label, $period);
- })->toArray();
-
- $tooltip_labels = array_combine($labels, $formatted_dates);
-
$chart_datasets = [
[
'label' => __('Visits'),
'hash',
'date',
'fluidbook',
+ 'fluidbook_settings',
'start_date',
'end_date',
'report_timespan',
'page_count',
- 'labels',
'tooltip_labels',
'formatted_date_range',
'chart_heading',
$hash = $fluidbook->hash;
if (!$fluidbook->stats) {
- return "Statistics are disabled for this Fluidbook #{$fluidbook_id} ({$fluidbook->name})";
+ return "Statistics are disabled for this Fluidbook #{$fluidbook_id} ({$settings->title})";
}
return redirect()->route('stats', compact('fluidbook_id', 'hash'));
return view('fluidbook_stats.API', compact('matomo_tokens'));
}
+ // Format a date range for display in the interface
+ protected function formatDateRange($start_date, $end_date): string {
+
+ $start = Carbon::parse($start_date);
+ $end = Carbon::parse($end_date);
+ $crosses_month_boundary = $end->isoFormat('YYYY-MM') > $start->isoFormat('YYYY-MM');
+ $crosses_year_boundary = $end->isoFormat('YYYY') > $start->isoFormat('YYYY');
+
+ // Default formatting for start and end dates according to Carbon isoFormat() function
+ $start_format = 'Do'; // Day with ordinal
+ $end_format = 'Do MMMM, YYYY';
+ $separator = $crosses_year_boundary || $crosses_month_boundary ? ' — ' : '—';
+
+ if ($crosses_year_boundary) {
+ // When a date range crosses a year boundary, we need to show the full dates
+ $start_format = 'MMMM Do, YYYY';
+ $end_format = 'MMMM Do, YYYY';
+ } elseif ($crosses_month_boundary) {
+ // When crossing a month boundary, show both month names
+ $start_format = 'MMMM Do';
+ $end_format = 'MMMM Do, YYYY';
+ }
+
+ return $start->isoFormat($start_format) . $separator . $end->isoFormat($end_format);
+ }
+
+
// Format dates depending on the segregation period (used for tooltips and stats detail tables)
protected function formatDateForPeriod($date, $period): string {