First commit
This commit is contained in:
14 files changed
+426
-139
No files matched your search
@@ -1,61 +1,80 @@
|
|||||||
# This is my package matomo-proxy-laravel
|
# Matomo Proxy for Laravel
|
||||||
|
|
||||||
[](https://packagist.org/packages/mattitjaab/matomo-proxy-laravel)
|
[](https://packagist.org/packages/mattitjaab/matomo-proxy-laravel)
|
||||||
[](https://github.com/mattitjaab/matomo-proxy-laravel/actions?query=workflow%3Arun-tests+branch%3Amain)
|
[](https://github.com/mattitjaab/matomo-proxy-laravel/actions?query=workflow%3Arun-tests+branch%3Amain)
|
||||||
[](https://github.com/mattitjaab/matomo-proxy-laravel/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain)
|
[](https://github.com/mattitjaab/matomo-proxy-laravel/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain)
|
||||||
[](https://packagist.org/packages/mattitjaab/matomo-proxy-laravel)
|
[](https://packagist.org/packages/mattitjaab/matomo-proxy-laravel)
|
||||||
|
|
||||||
This is where your description should go. Limit it to a paragraph or two. Consider adding a small example.
|
This package provides a plug-and-play **server-side Matomo tracking middleware** for Laravel.
|
||||||
|
Instead of embedding JavaScript trackers in your frontend, requests are tracked directly from your Laravel app to your Matomo instance, ensuring better privacy, ad-blocker resilience, and simplified integration.
|
||||||
## Support us
|
|
||||||
|
|
||||||
[<img src="https://github-ads.s3.eu-central-1.amazonaws.com/matomo-proxy-laravel.jpg?t=1" width="419px" />](https://spatie.be/github-ad-click/matomo-proxy-laravel)
|
|
||||||
|
|
||||||
We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).
|
|
||||||
|
|
||||||
We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
You can install the package via composer:
|
Install the package via Composer:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
composer require mattitjaab/matomo-proxy-laravel
|
composer require mattitjaab/matomo-proxy-laravel
|
||||||
```
|
```
|
||||||
|
|
||||||
You can publish and run the migrations with:
|
Publish the config file:
|
||||||
|
|
||||||
```bash
|
|
||||||
php artisan vendor:publish --tag="matomo-proxy-laravel-migrations"
|
|
||||||
php artisan migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
You can publish the config file with:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
php artisan vendor:publish --tag="matomo-proxy-laravel-config"
|
php artisan vendor:publish --tag="matomo-proxy-laravel-config"
|
||||||
```
|
```
|
||||||
|
|
||||||
This is the contents of the published config file:
|
This will create a `config/matomo-proxy-laravel.php` file. Example:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
return [
|
return [
|
||||||
|
'enabled' => env('MATOMO_ENABLED', true),
|
||||||
|
|
||||||
|
// Full Matomo tracking endpoint (must include /matomo.php)
|
||||||
|
'base_url' => env('MATOMO_BASE_URL', ''),
|
||||||
|
|
||||||
|
// Matomo site ID
|
||||||
|
'site_id' => env('MATOMO_SITE_ID', null),
|
||||||
|
|
||||||
|
// Optional token_auth (can be null for anonymous tracking)
|
||||||
|
'token' => env('MATOMO_TOKEN', null),
|
||||||
|
|
||||||
|
// Paths that should never be tracked
|
||||||
|
'ignore' => [
|
||||||
|
'telescope/*', 'horizon/*', 'health', '_debugbar/*',
|
||||||
|
],
|
||||||
|
|
||||||
|
// HTTP client behavior
|
||||||
|
'timeout' => env('MATOMO_TIMEOUT', 2),
|
||||||
|
'retry' => [
|
||||||
|
'times' => env('MATOMO_RETRY_TIMES', 0),
|
||||||
|
'sleep' => env('MATOMO_RETRY_SLEEP_MS', 100), // milliseconds
|
||||||
|
],
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
Optionally, you can publish the views using
|
|
||||||
|
|
||||||
```bash
|
|
||||||
php artisan vendor:publish --tag="matomo-proxy-laravel-views"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
Register the middleware globally in your `bootstrap/app.php`:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$matomoProxyLaravel = new MattitjaAB\MatomoProxyLaravel();
|
->withMiddleware(function (Middleware $middleware): void {
|
||||||
echo $matomoProxyLaravel->echoPhrase('Hello, MattitjaAB!');
|
$middleware->append(\MattitjaAB\MatomoProxyLaravel\Middleware\MatomoProxyLaravelMiddleware::class);
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2. Configure your `.env` file:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
MATOMO_ENABLED=true
|
||||||
|
MATOMO_BASE_URL=https://analytics.example.com/matomo.php
|
||||||
|
MATOMO_SITE_ID=1
|
||||||
|
MATOMO_TOKEN=null
|
||||||
|
MATOMO_TIMEOUT=2
|
||||||
|
MATOMO_RETRY_TIMES=0
|
||||||
|
MATOMO_RETRY_SLEEP_MS=100
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ That’s it. All requests will now be tracked server-side in Matomo without requiring any frontend JS snippet.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -66,18 +85,10 @@ composer test
|
|||||||
|
|
||||||
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
|
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
|
|
||||||
|
|
||||||
## Security Vulnerabilities
|
|
||||||
|
|
||||||
Please review [our security policy](../../security/policy) on how to report security vulnerabilities.
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
- [MattitjaAB](https://github.com/MattitjaAB)
|
* [MattitjaAB](https://github.com/MattitjaAB)
|
||||||
- [All Contributors](../../contributors)
|
* [All Contributors](../../contributors)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
+1
-4
@@ -63,10 +63,7 @@
|
|||||||
"laravel": {
|
"laravel": {
|
||||||
"providers": [
|
"providers": [
|
||||||
"MattitjaAB\\MatomoProxyLaravel\\MatomoProxyLaravelServiceProvider"
|
"MattitjaAB\\MatomoProxyLaravel\\MatomoProxyLaravelServiceProvider"
|
||||||
],
|
]
|
||||||
"aliases": {
|
|
||||||
"MatomoProxyLaravel": "MattitjaAB\\MatomoProxyLaravel\\Facades\\MatomoProxyLaravel"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
|
|||||||
@@ -1,6 +1,28 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// config for MattitjaAB/MatomoProxyLaravel
|
|
||||||
return [
|
return [
|
||||||
|
// Enable/disable tracking
|
||||||
|
'enabled' => env('MATOMO_ENABLED', true),
|
||||||
|
|
||||||
|
// Full Matomo tracking endpoint (must include /matomo.php)
|
||||||
|
// Example: https://analytics.example.com/matomo.php
|
||||||
|
'base_url' => env('MATOMO_BASE_URL', ''),
|
||||||
|
|
||||||
|
// Matomo site ID
|
||||||
|
'site_id' => env('MATOMO_SITE_ID', null),
|
||||||
|
|
||||||
|
// Optional token_auth (can be null for anonymous tracking)
|
||||||
|
'token' => env('MATOMO_TOKEN', null),
|
||||||
|
|
||||||
|
// Paths that should never be tracked
|
||||||
|
'ignore' => [
|
||||||
|
'telescope/*', 'horizon/*', 'health', '_debugbar/*',
|
||||||
|
],
|
||||||
|
|
||||||
|
// HTTP client behavior
|
||||||
|
'timeout' => env('MATOMO_TIMEOUT', 2),
|
||||||
|
'retry' => [
|
||||||
|
'times' => env('MATOMO_RETRY_TIMES', 0),
|
||||||
|
'sleep' => env('MATOMO_RETRY_SLEEP_MS', 100), // milliseconds
|
||||||
|
],
|
||||||
];
|
];
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace MattitjaAB\MatomoProxyLaravel\Database\Factories;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
|
||||||
|
|
||||||
/*
|
|
||||||
class ModelFactory extends Factory
|
|
||||||
{
|
|
||||||
protected $model = YourModel::class;
|
|
||||||
|
|
||||||
public function definition()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration
|
|
||||||
{
|
|
||||||
public function up()
|
|
||||||
{
|
|
||||||
Schema::create('matomo_proxy_laravel_table', function (Blueprint $table) {
|
|
||||||
$table->id();
|
|
||||||
|
|
||||||
// add fields
|
|
||||||
|
|
||||||
$table->timestamps();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
+1
-2
@@ -5,8 +5,7 @@ parameters:
|
|||||||
level: 5
|
level: 5
|
||||||
paths:
|
paths:
|
||||||
- src
|
- src
|
||||||
- config
|
|
||||||
- database
|
|
||||||
tmpDir: build/phpstan
|
tmpDir: build/phpstan
|
||||||
checkOctaneCompatibility: true
|
checkOctaneCompatibility: true
|
||||||
checkModelProperties: true
|
checkModelProperties: true
|
||||||
|
|
||||||
Whitespace-only changes.
@@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace MattitjaAB\MatomoProxyLaravel\Commands;
|
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
|
|
||||||
class MatomoProxyLaravelCommand extends Command
|
|
||||||
{
|
|
||||||
public $signature = 'matomo-proxy-laravel';
|
|
||||||
|
|
||||||
public $description = 'My command';
|
|
||||||
|
|
||||||
public function handle(): int
|
|
||||||
{
|
|
||||||
$this->comment('All done');
|
|
||||||
|
|
||||||
return self::SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace MattitjaAB\MatomoProxyLaravel\Facades;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Facade;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see \MattitjaAB\MatomoProxyLaravel\MatomoProxyLaravel
|
|
||||||
*/
|
|
||||||
class MatomoProxyLaravel extends Facade
|
|
||||||
{
|
|
||||||
protected static function getFacadeAccessor(): string
|
|
||||||
{
|
|
||||||
return \MattitjaAB\MatomoProxyLaravel\MatomoProxyLaravel::class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace MattitjaAB\MatomoProxyLaravel;
|
|
||||||
|
|
||||||
class MatomoProxyLaravel {}
|
|
||||||
@@ -2,24 +2,23 @@
|
|||||||
|
|
||||||
namespace MattitjaAB\MatomoProxyLaravel;
|
namespace MattitjaAB\MatomoProxyLaravel;
|
||||||
|
|
||||||
use MattitjaAB\MatomoProxyLaravel\Commands\MatomoProxyLaravelCommand;
|
use Illuminate\Contracts\Http\Kernel as HttpKernel;
|
||||||
|
use MattitjaAB\MatomoProxyLaravel\Middleware\MatomoProxyLaravelMiddleware;
|
||||||
use Spatie\LaravelPackageTools\Package;
|
use Spatie\LaravelPackageTools\Package;
|
||||||
use Spatie\LaravelPackageTools\PackageServiceProvider;
|
use Spatie\LaravelPackageTools\PackageServiceProvider;
|
||||||
|
|
||||||
class MatomoProxyLaravelServiceProvider extends PackageServiceProvider
|
final class MatomoProxyLaravelServiceProvider extends PackageServiceProvider
|
||||||
{
|
{
|
||||||
public function configurePackage(Package $package): void
|
public function configurePackage(Package $package): void
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* This class is a Package Service Provider
|
|
||||||
*
|
|
||||||
* More info: https://github.com/spatie/laravel-package-tools
|
|
||||||
*/
|
|
||||||
$package
|
$package
|
||||||
->name('matomo-proxy-laravel')
|
->name('matomo-proxy-laravel')
|
||||||
->hasConfigFile()
|
->hasConfigFile('matomo-proxy-laravel');
|
||||||
->hasViews()
|
}
|
||||||
->hasMigration('create_matomo_proxy_laravel_table')
|
|
||||||
->hasCommand(MatomoProxyLaravelCommand::class);
|
public function packageBooted(): void
|
||||||
|
{
|
||||||
|
$this->app->make(HttpKernel::class)
|
||||||
|
->pushMiddleware(MatomoProxyLaravelMiddleware::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace MattitjaAB\MatomoProxyLaravel\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
final class MatomoProxyLaravelMiddleware
|
||||||
|
{
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
/** @var Response $response */
|
||||||
|
$response = $next($request);
|
||||||
|
|
||||||
|
// Only track GET requests
|
||||||
|
if (! $request->isMethod('GET')) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global feature toggle + required config
|
||||||
|
if (! $this->isEnabled()) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only track HTML responses
|
||||||
|
if (! $this->isHtmlResponse($response)) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Respect ignore patterns
|
||||||
|
if ($this->isIgnoredPath($request)) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip non-success/redirect responses (e.g., 404, 5xx)
|
||||||
|
if (! $this->isTrackableStatus($response)) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure endpoint is present
|
||||||
|
$endpoint = $this->buildEndpoint();
|
||||||
|
if ($endpoint === null) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build payload now; do not capture Request in any deferred closure
|
||||||
|
$params = $this->buildParams($request);
|
||||||
|
|
||||||
|
// Send synchronously (you can swap to app()->terminating() if desired)
|
||||||
|
$this->send($endpoint, $params);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enabled flag and required keys.
|
||||||
|
*/
|
||||||
|
private function isEnabled(): bool
|
||||||
|
{
|
||||||
|
return config('matomo-proxy-laravel.enabled') === true
|
||||||
|
&& filled(config('matomo-proxy-laravel.base_url'))
|
||||||
|
&& filled(config('matomo-proxy-laravel.site_id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only track HTML (also accept application/xhtml+xml).
|
||||||
|
*/
|
||||||
|
private function isHtmlResponse(Response $response): bool
|
||||||
|
{
|
||||||
|
$contentType = $response->headers->get('content-type');
|
||||||
|
|
||||||
|
return $contentType !== null
|
||||||
|
&& (str_starts_with($contentType, 'text/html')
|
||||||
|
|| str_starts_with($contentType, 'application/xhtml+xml'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respect configurable ignore patterns.
|
||||||
|
*/
|
||||||
|
private function isIgnoredPath(Request $request): bool
|
||||||
|
{
|
||||||
|
foreach (config('matomo-proxy-laravel.ignore', []) as $pattern) {
|
||||||
|
if ($request->is($pattern)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count only successful (2xx) and redirect (3xx) responses.
|
||||||
|
*/
|
||||||
|
private function isTrackableStatus(Response $response): bool
|
||||||
|
{
|
||||||
|
$code = $response->getStatusCode();
|
||||||
|
|
||||||
|
return $code >= 200 && $code < 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Endpoint must already include /matomo.php.
|
||||||
|
*/
|
||||||
|
private function buildEndpoint(): ?string
|
||||||
|
{
|
||||||
|
$endpoint = config('matomo-proxy-laravel.base_url');
|
||||||
|
|
||||||
|
return filled($endpoint) ? trim((string) $endpoint) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build Matomo Tracking API payload.
|
||||||
|
*/
|
||||||
|
private function buildParams(Request $request): array
|
||||||
|
{
|
||||||
|
$params = [
|
||||||
|
'idsite' => (string) config('matomo-proxy-laravel.site_id', ''),
|
||||||
|
'rec' => 1,
|
||||||
|
'apiv' => 1,
|
||||||
|
'url' => $request->fullUrl(),
|
||||||
|
'action_name' => $request->route()?->getName() ?: $request->path(),
|
||||||
|
'ua' => $request->userAgent(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($ref = $request->headers->get('referer')) {
|
||||||
|
$params['urlref'] = $ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($lang = $request->headers->get('accept-language')) {
|
||||||
|
$params['lang'] = $lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ip = $request->ip()) {
|
||||||
|
$params['cip'] = $ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($token = trim((string) config('matomo-proxy-laravel.token', ''))) {
|
||||||
|
$params['token_auth'] = $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($uid = $request->user()->id ?? null) {
|
||||||
|
$params['uid'] = (string) $uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the HTTP request (synchronous).
|
||||||
|
*/
|
||||||
|
private function send(string $endpoint, array $params): void
|
||||||
|
{
|
||||||
|
$timeout = (int) config('matomo-proxy-laravel.timeout', 2);
|
||||||
|
$retryTimes = (int) config('matomo-proxy-laravel.retry.times', 0);
|
||||||
|
$retrySleep = (int) config('matomo-proxy-laravel.retry.sleep.ms', 100);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Http::asForm()
|
||||||
|
->timeout($timeout)
|
||||||
|
->retry($retryTimes, $retrySleep)
|
||||||
|
->post($endpoint, $params);
|
||||||
|
} catch (\Throwable) {
|
||||||
|
// Never let analytics affect the response lifecycle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
it('can test', function () {
|
|
||||||
expect(true)->toBeTrue();
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Http\Client\Request as HttpClientRequest;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use MattitjaAB\MatomoProxyLaravel\Middleware\MatomoProxyLaravelMiddleware;
|
||||||
|
|
||||||
|
it('sends a tracking hit and includes user id when authenticated', function () {
|
||||||
|
config()->set('matomo-proxy-laravel.enabled', true);
|
||||||
|
config()->set('matomo-proxy-laravel.base_url', 'https://matomo.example/matomo.php');
|
||||||
|
config()->set('matomo-proxy-laravel.site_id', '1');
|
||||||
|
config()->set('matomo-proxy-laravel.token', 'secret-token');
|
||||||
|
|
||||||
|
Http::preventStrayRequests();
|
||||||
|
Http::fake([
|
||||||
|
'https://matomo.example/matomo.php' => Http::response('OK', 200),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = new class implements \Illuminate\Contracts\Auth\Authenticatable
|
||||||
|
{
|
||||||
|
public int $id = 123;
|
||||||
|
|
||||||
|
public function getAuthIdentifierName()
|
||||||
|
{
|
||||||
|
return 'id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthIdentifier()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthPasswordName()
|
||||||
|
{
|
||||||
|
return 'password';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthPassword()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRememberToken()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRememberToken($value): void {}
|
||||||
|
|
||||||
|
public function getRememberTokenName()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Route::get('/page', fn () => response('ok', 200, ['Content-Type' => 'text/html']))
|
||||||
|
->name('test.route');
|
||||||
|
|
||||||
|
$this->be($user);
|
||||||
|
|
||||||
|
$this->get('/page', [
|
||||||
|
'Accept-Language' => 'sv-SE',
|
||||||
|
'User-Agent' => 'PHPUnit',
|
||||||
|
'Referer' => 'https://ref.example',
|
||||||
|
])->assertOk();
|
||||||
|
|
||||||
|
Http::assertSent(function (HttpClientRequest $request) {
|
||||||
|
$params = $request->data();
|
||||||
|
|
||||||
|
return $request->url() === 'https://matomo.example/matomo.php'
|
||||||
|
&& $request->method() === 'POST'
|
||||||
|
&& ($params['idsite'] ?? null) === '1'
|
||||||
|
&& ($params['uid'] ?? null) === '123'
|
||||||
|
&& ($params['token_auth'] ?? null) === 'secret-token'
|
||||||
|
&& ($params['action_name'] ?? null) === 'test.route'
|
||||||
|
&& ($params['urlref'] ?? null) === 'https://ref.example'
|
||||||
|
&& ($params['lang'] ?? null) === 'sv-SE'
|
||||||
|
&& ($params['ua'] ?? null) === 'PHPUnit'
|
||||||
|
&& ($params['rec'] ?? null) === 1
|
||||||
|
&& ($params['apiv'] ?? null) === 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
Http::assertSentCount(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does nothing when disabled', function () {
|
||||||
|
config()->set('matomo-proxy-laravel.enabled', false);
|
||||||
|
config()->set('matomo-proxy-laravel.base_url', 'https://matomo.example/matomo.php');
|
||||||
|
config()->set('matomo-proxy-laravel.site_id', '1');
|
||||||
|
|
||||||
|
Http::fake();
|
||||||
|
|
||||||
|
Route::get('/disabled', fn () => 'ok')
|
||||||
|
->middleware(MatomoProxyLaravelMiddleware::class);
|
||||||
|
|
||||||
|
$this->get('/disabled')->assertOk();
|
||||||
|
|
||||||
|
Http::assertNothingSent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('never breaks the response when exceptions occur during tracking', function () {
|
||||||
|
config()->set('matomo-proxy-laravel.enabled', true);
|
||||||
|
config()->set('matomo-proxy-laravel.base_url', 'https://matomo.example/matomo.php');
|
||||||
|
config()->set('matomo-proxy-laravel.site_id', '1');
|
||||||
|
|
||||||
|
Http::fake(function () {
|
||||||
|
throw new Exception('network error');
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::get('/exception', fn () => 'ok')
|
||||||
|
->middleware(MatomoProxyLaravelMiddleware::class);
|
||||||
|
|
||||||
|
$this->get('/exception')->assertOk();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not send tracking for non-get requests', function () {
|
||||||
|
config()->set('matomo-proxy-laravel.enabled', true);
|
||||||
|
config()->set('matomo-proxy-laravel.base_url', 'https://matomo.example/matomo.php');
|
||||||
|
config()->set('matomo-proxy-laravel.site_id', '1');
|
||||||
|
|
||||||
|
Http::fake();
|
||||||
|
|
||||||
|
Route::post('/post', fn () => 'ok')
|
||||||
|
->middleware(MatomoProxyLaravelMiddleware::class);
|
||||||
|
|
||||||
|
$this->post('/post')->assertOk();
|
||||||
|
|
||||||
|
Http::assertNothingSent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not send tracking for ignored paths', function () {
|
||||||
|
config()->set('matomo-proxy-laravel.enabled', true);
|
||||||
|
config()->set('matomo-proxy-laravel.base_url', 'https://matomo.example/matomo.php');
|
||||||
|
config()->set('matomo-proxy-laravel.site_id', '1');
|
||||||
|
config()->set('matomo-proxy-laravel.ignore', ['ignored*']);
|
||||||
|
|
||||||
|
Http::fake();
|
||||||
|
|
||||||
|
Route::get('/ignored/page', fn () => 'ok')
|
||||||
|
->middleware(MatomoProxyLaravelMiddleware::class);
|
||||||
|
|
||||||
|
$this->get('/ignored/page')->assertOk();
|
||||||
|
|
||||||
|
Http::assertNothingSent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not send tracking for non-html responses', function () {
|
||||||
|
config()->set('matomo-proxy-laravel.enabled', true);
|
||||||
|
config()->set('matomo-proxy-laravel.base_url', 'https://matomo.example/matomo.php');
|
||||||
|
config()->set('matomo-proxy-laravel.site_id', '1');
|
||||||
|
|
||||||
|
Http::fake();
|
||||||
|
|
||||||
|
Route::get('/json', fn () => response()->json(['ok' => true]))
|
||||||
|
->middleware(MatomoProxyLaravelMiddleware::class);
|
||||||
|
|
||||||
|
$this->get('/json')->assertOk();
|
||||||
|
|
||||||
|
Http::assertNothingSent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not send tracking for 404 responses', function () {
|
||||||
|
config()->set('matomo-proxy-laravel.enabled', true);
|
||||||
|
config()->set('matomo-proxy-laravel.base_url', 'https://matomo.example/matomo.php');
|
||||||
|
config()->set('matomo-proxy-laravel.site_id', '1');
|
||||||
|
|
||||||
|
Http::fake();
|
||||||
|
|
||||||
|
$this->get('/nonexistent')->assertNotFound();
|
||||||
|
|
||||||
|
Http::assertNothingSent();
|
||||||
|
});
|
||||||
Reference in new issue
Block a user