Deep dive into the configuration and assets associated with this component.
| Name | api-graphics |
|---|---|
| Display Name | API Graphics |
| Version | 1.0.0 |
| Status | Active |
| Downloads | 89 |
| Description | Component: API Graphics |
| Created | 2025-11-11 20:42:10 |
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ApiGraphicsController extends Controller
{
/**
* Display the API graphics interface.
*/
public function index(Request $request)
{
// Get Matomo configuration from authenticated user
$user = auth()->user();
if (!$user || !$user->matomo_configured) {
return redirect()->route('onboarding')->with('error', 'Please configure your Matomo instance first.');
}
// Use global Matomo configuration from user profile
$matomoUrl = $user->matomo_url;
$matomoToken = $user->matomo_token ? decrypt($user->matomo_token) : null;
$siteId = $user->matomo_site_id ?? 1;
// Get dynamic parameters from URL (period, date, segment)
$period = $request->get('period', 'day');
$date = $request->get('date', 'today');
$segment = $request->get('segment', '');
// Format is always JSON for using tools directly
$format = 'json';
// Fetch Matomo data server-side to avoid Cloudflare blocking
$matomoData = $this->fetchMatomoDataWithConfig($matomoUrl, $matomoToken, $siteId, $period, $date, $segment, $format);
return view('components.api-graphics.index', compact('matomoData', 'matomoUrl', 'matomoToken', 'siteId', 'period', 'date', 'segment'));
}
private function fetchMatomoDataWithConfig($matomoUrl, $token, $siteId, $period, $date, $segment = '', $format = 'json')
{
$baseUrl = rtrim($matomoUrl, '/') . '/index.php';
try {
// Initialize data structure
$data = [
'visits' => [],
'pageviews' => [],
'countries' => [],
'countryVisits' => [],
'devices' => [],
'deviceVisits' => [],
'referrers' => [],
'referrerVisits' => [],
'goals' => [],
'goalConversions' => [],
'topPages' => [],
'pageVisits' => []
];
$context = stream_context_create([
'http' => [
'timeout' => 30,
'method' => 'GET',
'header' => 'User-Agent: Laravel Matomo Dashboard'
]
]);
// Build base parameters
$baseParams = [
'module' => 'API',
'idSite' => $siteId,
'period' => $period,
'date' => $date,
'format' => $format,
'token_auth' => $token,
];
if ($segment && $segment !== '' && $segment !== 'undefined') {
$baseParams['segment'] = $segment;
}
// Fetch visits summary
$visitsSummaryUrl = $baseUrl . '?' . http_build_query(array_merge($baseParams, ['method' => 'VisitsSummary.get']));
$response = file_get_contents($visitsSummaryUrl, false, $context);
if ($response !== false) {
$summary = json_decode($response, true);
if ($summary) {
$data['visits_summary'] = $summary;
\Illuminate\Support\Facades\Log::info('Matomo visits summary fetched:', $summary);
} else {
\Illuminate\Support\Facades\Log::warning('Failed to decode visits summary response:', ['response' => $response]);
}
} else {
\Illuminate\Support\Facades\Log::error('Failed to fetch visits summary from Matomo API');
}
// Fetch visits over time - use VisitsSummary.get for historical data
// For range periods, get last 30 days
$visitsDate = $date;
if ($period === 'day' && $date === 'today') {
// For today, get last 30 days
$visitsDate = 'last30';
} elseif ($period === 'day' && $date === 'yesterday') {
// For yesterday, get last 30 days ending yesterday
$yesterday = date('Y-m-d', strtotime('-1 day'));
$visitsDate = date('Y-m-d', strtotime('-30 days')) . ',' . $yesterday;
} elseif ($period === 'range') {
// For range, use the range
$visitsDate = $date;
} else {
// For other periods, get last 30 days
$visitsDate = 'last30';
}
// Use VisitsSummary.get which returns data indexed by date
$visitsOverTimeParams = array_merge($baseParams, [
'method' => 'VisitsSummary.get',
'date' => $visitsDate
]);
$visitsOverTimeUrl = $baseUrl . '?' . http_build_query($visitsOverTimeParams);
$response = @file_get_contents($visitsOverTimeUrl, false, $context);
if ($response !== false) {
$visitsData = json_decode($response, true);
if ($visitsData && (!isset($visitsData['result']) || $visitsData['result'] !== 'error')) {
// Handle the response format: dates as keys, each value is an array with nb_visits, nb_actions, etc.
if (is_array($visitsData)) {
// Extract labels (dates) and visit counts
$labels = array_keys($visitsData);
$visits = array_map(function($v) {
return $v['nb_visits'] ?? 0;
}, $visitsData);
$pageviews = array_map(function($v) {
return $v['nb_actions'] ?? 0;
}, $visitsData);
$data['visits'] = array_values($visits);
$data['pageviews'] = array_values($pageviews);
\Illuminate\Support\Facades\Log::info('Visits over time fetched:', [
'count' => count($data['visits']),
'first_few' => array_slice($data['visits'], 0, 5)
]);
} elseif (isset($visitsData['nb_visits'])) {
// Single day data - get historical data instead
$historicalParams = array_merge($baseParams, [
'method' => 'VisitsSummary.get',
'date' => 'last30'
]);
$historicalUrl = $baseUrl . '?' . http_build_query($historicalParams);
$historicalResponse = @file_get_contents($historicalUrl, false, $context);
if ($historicalResponse !== false) {
$historicalData = json_decode($historicalResponse, true);
if (is_array($historicalData)) {
$visits = array_map(function($v) {
return $v['nb_visits'] ?? 0;
}, $historicalData);
$pageviews = array_map(function($v) {
return $v['nb_actions'] ?? 0;
}, $historicalData);
$data['visits'] = array_values($visits);
$data['pageviews'] = array_values($pageviews);
}
}
}
}
}
// Fetch countries data
$countriesUrl = $baseUrl . '?' . http_build_query(array_merge($baseParams, ['method' => 'UserCountry.getCountry']));
$response = file_get_contents($countriesUrl, false, $context);
if ($response !== false) {
$countriesData = json_decode($response, true);
if (is_array($countriesData)) {
$countriesData = array_slice($countriesData, 0, 10);
foreach ($countriesData as $country) {
$data['countries'][] = $country['label'] ?? 'Unknown';
$data['countryVisits'][] = $country['nb_visits'] ?? 0;
}
}
}
// Fetch top pages data
$topPagesUrl = $baseUrl . '?' . http_build_query(array_merge($baseParams, ['method' => 'Actions.getPageUrls']));
$response = file_get_contents($topPagesUrl, false, $context);
if ($response !== false) {
$pagesData = json_decode($response, true);
if (is_array($pagesData)) {
$pagesData = array_slice($pagesData, 0, 10);
foreach ($pagesData as $page) {
$data['topPages'][] = $page['label'] ?? 'Unknown Page';
$data['pageVisits'][] = $page['nb_visits'] ?? 0;
}
}
}
// Fetch devices data
$devicesUrl = $baseUrl . '?' . http_build_query(array_merge($baseParams, ['method' => 'DevicesDetection.getType']));
$response = file_get_contents($devicesUrl, false, $context);
if ($response !== false) {
$devicesData = json_decode($response, true);
if (is_array($devicesData)) {
foreach ($devicesData as $device) {
$data['devices'][] = $device['label'] ?? 'Unknown';
$data['deviceVisits'][] = $device['nb_visits'] ?? 0;
}
}
}
// Fetch referrers data
$referrersUrl = $baseUrl . '?' . http_build_query(array_merge($baseParams, ['method' => 'Referrers.getReferrerType']));
$response = file_get_contents($referrersUrl, false, $context);
if ($response !== false) {
$referrersData = json_decode($response, true);
if (is_array($referrersData)) {
$referrersData = array_slice($referrersData, 0, 10);
foreach ($referrersData as $referrer) {
$data['referrers'][] = $referrer['label'] ?? 'Unknown';
$data['referrerVisits'][] = $referrer['nb_visits'] ?? 0;
}
}
}
// Fetch goals data
$goalsUrl = $baseUrl . '?' . http_build_query(array_merge($baseParams, ['method' => 'Goals.get']));
$response = file_get_contents($goalsUrl, false, $context);
if ($response !== false) {
$goalsData = json_decode($response, true);
if (is_array($goalsData)) {
foreach ($goalsData as $goal) {
$data['goals'][] = $goal['label'] ?? 'Unknown Goal';
$data['goalConversions'][] = $goal['nb_conversions'] ?? 0;
}
}
}
// Ensure visits_summary is always set
if (!isset($data['visits_summary'])) {
$data['visits_summary'] = null;
}
return $data;
} catch (\Exception $e) {
\Illuminate\Support\Facades\Log::error('Matomo API Error: ' . $e->getMessage());
return [
'visits' => [],
'pageviews' => [],
'countries' => [],
'countryVisits' => [],
'devices' => [],
'deviceVisits' => [],
'referrers' => [],
'referrerVisits' => [],
'goals' => [],
'goalConversions' => [],
'topPages' => [],
'pageVisits' => [],
'visits_summary' => null,
'error' => $e->getMessage()
];
}
}
}
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ApiGraphicsController;
Route::middleware(['auth', 'component.visible'])->group(function () {
Route::get('/api-graphics', [ApiGraphicsController::class, 'index'])->name('dashboard.api-graphics');
});
index.blade.php
Length: 191829 chars