Skip to content

Symfony Bundle

Automatic server-side page views via kernel.terminate and semantic configuration. Compatible with Symfony 6.4 and 7, PHP ≥ 8.1.

Installation

composer require quiet-metrics/symfony-metrics

Without Symfony Flex, register the bundle:

// config/bundles.php
return [
    // …
    QuietMetrics\Symfony\QuietMetricsBundle::class => ['all' => true],
];

Upgrading

Each 0.x minor version of the bundle requires the matching minor version of the core SDK quiet-metrics/php-metrics: upgrade both together, and only those two.

composer require quiet-metrics/symfony-metrics:^0.5 --no-update
composer update quiet-metrics/symfony-metrics quiet-metrics/php-metrics

A plain composer require fails, because the core SDK is locked in composer.lock. Composer's error message then suggests -W, which updates every dependency of the project; -w would also upgrade Symfony components. Read the package CHANGELOG before upgrading: it flags changes in what gets counted.

Configuration

# config/packages/quiet_metrics.yaml
quiet_metrics:
    public_key: '%env(QUIET_METRICS_PUBLIC_KEY)%'   # the site's public key (required)
    secret_key: '%env(QUIET_METRICS_SECRET_KEY)%'   # required for server-side sending: signs every send (HMAC)

    # endpoint: 'https://quietmetrics.dev/api/v1/collect'  # core SDK default
    # auto_pageview: false        # disables the automatic page view

Per environment, override in config/packages/test/quiet_metrics.yaml or via environment variables; without a valid public key, nothing is sent.

Automatic page views

Automatic pageviews are HTML/XHTML documents rendered in response to a GET, including 404/500 errors. Redirects, empty responses (204/205), PDFs, JSON and attachments are excluded, along with AJAX, announced prefetches and opted-out visitors.

From version 0.4.0, track_404: true also emits a 404 event with the page path. This option is off by default: each additional event consumes quota. Enable it server-side or through the script’s data-404 on a given page to avoid duplicate events. Server tracking cannot see pages served by a cache that bypasses PHP.

auto_pageview: false turns the listener off: you keep the client for manual sends (mixed sites, selective tracking).

Events

Inject QuietMetrics\Tracker, the interface the client implements (public service; QuietMetrics\Client before version 0.5.0):

use QuietMetrics\Tracker;

final class CheckoutController
{
    public function __construct(private readonly Tracker $quietMetrics) {}

    public function confirm(): Response
    {
        // …
        $this->quietMetrics->event('purchase', ['amount' => 49, 'plan' => 'pro']);
    }
}

From a console command or a Messenger worker, there is no current request: pass the URL explicitly, otherwise nothing is sent (silent drop):

$this->quietMetrics->event('import-completed', ['rows' => 1200], [
    'url' => 'https://mysite.com/imports',
]);

Edge cases

Full-page cache (Varnish, Cloudflare, response cache…). A page served from a cache in front of your application never runs PHP, so its visit is not counted. Keep those pages out of the cache, or add the qm.js script as well: both measurements coexist without double counting.

FrankenPHP, RoadRunner, persistent workers. The listener reads each request's Request object, never the superglobals. Nothing to configure.

Reverse proxy / CDN. The listener uses Request::getClientIp(): configure framework.trusted_proxies as usual and the visitor's real IP will follow. The SDK's trust_proxy_headers option only applies to usage outside the framework.

What gets sent. From version 0.5.0, the SDK only sends what Quiet Metrics reads: the page address reduced to its origin, its path and its campaign parameters, and the referrer reduced to its origin. Details in the PHP SDK.

Tests. Replace the QuietMetrics\Tracker service with your own implementation to verify your events without any network. The client is final: you do not extend it, you replace the interface it implements (version 0.5.0 and later).

# config/services_test.yaml
services:
    QuietMetrics\Tracker:
        class: App\Tests\Double\RecordingTracker

Your code must then type-hint QuietMetrics\Tracker, as in the events example.

Robustness contract

Non-blocking sends (fire-and-forget socket, short cURL fallback), silent failures: analytics never breaks the host application, even if the platform is unreachable.

Can't find your answer?

Support replies on business days.