/Docs

Laravel integration

This guide targets Laravel 10+ running on PHP 8.2 or later. The avsbhq/avsb-php package ships a Laravel ServiceProvider that registers the SDK as a singleton, a Facade for ergonomic flag access, and per-request middleware for automatic context scoping. By the end you will be reading flags in controllers and Blade templates and tracking conversions with one line of code.

1

Install

terminal
bash
1composer require avsbhq/avsb-php
2

Obtain your SDK key

Open your A vs B project, go to Settings → Environments, and copy the Server SDK key. Add it to your .env file:

.env
bash
1AVSB_SDK_KEY=sdk_production_...
3

Publish and configure

Publish the default config file, then confirm your SDK key is referenced from the environment:

terminal
bash
1php artisan vendor:publish --provider="Avsb\Laravel\AvsbServiceProvider"
config/avsb.php
php
1<?php
2
3return [
4 'sdk_key' => env('AVSB_SDK_KEY'),
5
6 /*
7 |--------------------------------------------------------------------------
8 | Context factory
9 |--------------------------------------------------------------------------
10 | A callable that receives the current Request and returns an EvalContext
11 | array. Used by the per-request middleware.
12 */
13 'context_from' => function (\Illuminate\Http\Request $request): array {
14 return [
15 'kind' => 'user',
16 'key' => (string) ($request->user()?->id ?? 'anon'),
17 'plan' => $request->user()?->plan ?? 'free',
18 ];
19 },
20];
4

Register the middleware

Add the per-request middleware to your HTTP kernel so every route gets a scoped flag helper automatically.

app/Http/Kernel.php
php
1protected $middlewareGroups = [
2 'web' => [
3 // ... existing middleware ...
4 \Avsb\Laravel\Middleware\AvsbRequestMiddleware::class,
5 ],
6 'api' => [
7 // ... existing middleware ...
8 \Avsb\Laravel\Middleware\AvsbRequestMiddleware::class,
9 ],
10];
5

Read a flag via the Facade

app/Http/Controllers/CheckoutController.php
php
1<?php
2
3namespace App\Http\Controllers;
4
5use Avsb\Laravel\Facades\Avsb;
6use Illuminate\Http\JsonResponse;
7
8class CheckoutController extends Controller
9{
10 public function show(): JsonResponse
11 {
12 $showNew = Avsb::getBoolFlag('checkout-v2', false);
13 $theme = Avsb::getStringFlag('ui-theme', 'default');
14
15 return response()->json([
16 'showNewCheckout' => $showNew,
17 'theme' => $theme,
18 ]);
19 }
20}
Facade vs container injection
The Facade resolves to the request-scoped client set by the middleware. If you prefer dependency injection, type-hint Avsb\AvsbClient in your controller constructor — the container will resolve the same scoped instance.
6

Track an event

php
1Avsb::track('purchase', ['value' => 149.99, 'properties' => ['currency' => 'usd']]);
7

Identify a user

To evaluate flags for a user different from the one resolved by middleware — for example after an API authentication step — retrieve the underlying server from the container and scope manually:

php
1use AvsbAvsbServer;
2
3$server = app(AvsbServer::class);
4$scoped = $server->forUser([
5 'kind' => 'user',
6 'key' => (string) $user->id,
7 'plan' => $user->plan,
8]);
9$showNew = $scoped->getBoolFlag('checkout-v2', false);

Using flags in Blade templates

The ServiceProvider registers a Blade directive so you can gate blocks of template markup directly:

resources/views/checkout/show.blade.php
php
1@avsbFlag('checkout-v2', false)
2 @include('checkout.new')
3@else
4 @include('checkout.legacy')
5@endAvsbFlag

Graceful shutdown

Laravel's queue worker and scheduler flush the SDK automatically via the ServiceProvider's registered terminatingcallback. For long-running Octane workers, the ServiceProvider also hooks into Octane'sRequestTerminated event to flush pending events after each request.

Testing

tests/Feature/CheckoutTest.php
php
1<?php
2
3namespace Tests\Feature;
4
5use Avsb\Laravel\Testing\AvsbFake;
6use Tests\TestCase;
7
8class CheckoutTest extends TestCase
9{
10 public function test_shows_new_checkout_when_flag_on(): void
11 {
12 AvsbFake::flagOn('checkout-v2');
13
14 $response = $this->getJson('/checkout');
15
16 $response->assertJson(['showNewCheckout' => true]);
17 }
18
19 public function test_shows_legacy_checkout_by_default(): void
20 {
21 AvsbFake::flagOff('checkout-v2');
22
23 $response = $this->getJson('/checkout');
24
25 $response->assertJson(['showNewCheckout' => false]);
26 }
27}

What's next