Symfony Integration

The bext/symfony package provides a Symfony Flex bundle that auto-registers bext's cache, real-time, and task services for dependency injection.

Installation

composer require bext/symfony

Requirements: PHP >= 8.2, Symfony 6.4 or 7.0

The bundle is auto-registered via Symfony Flex — no manual configuration needed.

Autowiring

Inject bext services into any controller or service:

use Bext\Symfony\BextCache;
use Bext\Symfony\BextRealtime;
use Bext\Symfony\BextTasks;

class ProductController extends AbstractController
{
    public function __construct(
        private BextCache $cache,
        private BextRealtime $realtime,
        private BextTasks $tasks,
    ) {}

    #[Route('/api/products/{id}', methods: ['PUT'])]
    public function update(string $id, Request $request): JsonResponse
    {
        $product = $this->productRepo->update($id, $request->toArray());

        $this->cache->invalidate("products");
        $this->realtime->publish("products", [
            "action" => "updated",
            "id" => $id,
        ]);

        return $this->json($product);
    }
}

Container Aliases

Services are also available via container aliases:

$this->container->get('bext.cache');
$this->container->get('bext.realtime');
$this->container->get('bext.tasks');

Global Helpers

Same helper functions as the Laravel adapter:

bext_invalidate("products");
bext_publish("orders", ["id" => 123]);
bext_task("cleanup", "0 2 * * *", "cache::gc");

Cache API

class BextCache
{
    public function invalidate(string $tag): bool;
    public function invalidatePath(string $pattern): bool;
    public function flush(): bool;
}

Real-Time API

class BextRealtime
{
    public function publish(string $topic, mixed $data = null): bool;
}

Task Scheduling API

class BextTasks
{
    public function register(string $name, string $cron, string $command): bool;
    public function list(): array;
    public function cancel(string $name): bool;
}

Worker Mode

Like the Laravel adapter, Symfony supports worker mode for high-performance request handling.

Setup

Create a worker.php:

<?php
require __DIR__ . '/vendor/autoload.php';

$kernel = new \App\Kernel(
    $_SERVER['APP_ENV'] ?? 'prod',
    (bool) ($_SERVER['APP_DEBUG'] ?? false)
);

\Bext\Symfony\Worker::run($kernel);

Configure in bext.config.toml:

[php]
enabled = true
document_root = "./public"
workers = 4
worker_script = "./worker.php"
max_requests = 10000

Performance

Mode Latency Throughput
Classic 1–5ms ~1K req/s
Worker 34us ~15K req/s

The worker keeps Symfony's DI container, route matcher, and event dispatcher loaded in memory. Only request-specific state is re-created per request.

React SSR Bridge

Render React components from Symfony controllers:

use function Bext\Symfony\react;

#[Route('/dashboard')]
public function dashboard(): Response
{
    $html = react("Dashboard", [
        "user" => $this->getUser(),
        "metrics" => $this->metricsService->getSummary(),
    ]);

    return new Response($html);
}

Uses the same FFI-accelerated rendering path as the Laravel adapter when running in worker mode.

Event Subscriber Integration

You can integrate bext services with Symfony's event system:

use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class CacheInvalidationSubscriber implements EventSubscriberInterface
{
    public function __construct(private BextCache $cache) {}

    public static function getSubscribedEvents(): array
    {
        return [
            ProductUpdatedEvent::class => 'onProductUpdated',
        ];
    }

    public function onProductUpdated(ProductUpdatedEvent $event): void
    {
        $this->cache->invalidate("products");
        $this->cache->invalidatePath("/products/{$event->getProductId()}");
    }
}