Bundle Symfony
Pageviews serveur automatiques via kernel.terminate et configuration sémantique. Compatible Symfony 6.4 et 7, PHP ≥ 8.1.
Installation
composer require quiet-metrics/symfony-metrics
symfony-metrics n'est pas encore sur Packagist. Déclarez son dépôt GitHub (accès requis) ; le package cœur vient de Packagist :
{ "repositories": [ { "type": "vcs", "url": "https://github.com/Quiet-Metrics/symfony-metrics" } ] }
Sans Symfony Flex, enregistrez le bundle :
// config/bundles.php return [ // … QuietMetrics\Symfony\QuietMetricsBundle::class => ['all' => true], ];
Configuration
# config/packages/quiet_metrics.yaml quiet_metrics: public_key: '%env(QUIET_METRICS_PUBLIC_KEY)%' # clé publique du site (obligatoire) secret_key: '%env(QUIET_METRICS_SECRET_KEY)%' # facultative : signe chaque envoi (HMAC) # endpoint: 'https://quietmetrics.dev/api/v1/collect' # défaut du SDK cœur # auto_pageview: false # désactive la pageview automatique
Par environnement, surchargez dans config/packages/test/quiet_metrics.yaml ou via les variables d'environnement : sans clé publique valide, rien n'est envoyé.
Pageviews automatiques
Le listener écoute kernel.terminate : la réponse est déjà partie chez le visiteur, l'envoi n'ajoute aucune latence perçue. Seules les réponses HTML de requêtes GET réussies sont comptées. Ni XHR, ni erreurs, ni API JSON : vos endpoints REST ne polluent pas les statistiques.
auto_pageview: false coupe le listener : vous gardez le client pour des envois manuels (sites mixtes, tracking sélectif).
Événements
Injectez le client (service public) :
use QuietMetrics\Client; final class CheckoutController { public function __construct(private readonly Client $quietMetrics) {} public function confirm(): Response { // … $this->quietMetrics->event('achat', ['montant' => 49, 'plan' => 'pro']); } }
Depuis une commande console ou un worker Messenger, il n'y a pas de requête courante : passez l'URL explicitement, sinon rien ne part (abandon silencieux) :
$this->quietMetrics->event('import-termine', ['lignes' => 1200], [ 'url' => 'https://monsite.fr/imports', ]);
Cas particuliers
FrankenPHP, RoadRunner, workers persistants. Le listener lit l'objet Request de chaque requête, jamais les superglobales. Rien à configurer.
Reverse proxy / CDN. Le listener utilise Request::getClientIp() : configurez framework.trusted_proxies comme d'habitude et l'IP réelle du visiteur suivra. L'option trust_proxy_headers du SDK ne concerne que les usages hors framework.
Tests. Remplacez le service par un stub pour vérifier vos événements sans réseau :
# config/services_test.yaml services: QuietMetrics\Client: class: App\Tests\Double\NullQuietMetricsClient
Contrat de robustesse
Envoi non bloquant (socket fire-and-forget, repli cURL court), échecs silencieux : l'analytics ne casse jamais l'application hôte, même si la plateforme est injoignable.
Vous ne trouvez pas votre réponse ?
Le support répond en français, les jours ouvrés.