anbui/laravel-ab-experiments

Laravel A/B experiments

Maintainers

Package info

gitverse.ru/anbui/laravel-ab-experiments

pkg:composer/anbui/laravel-ab-experiments

Transparency log

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

dev-master 2026-05-06 17:04 UTC

This package is not auto-updated.

Last update: 2026-08-12 18:39:05 UTC


README

Пакет для A/B тестирования в Laravel.

Что умеет пакет

  • определяет, участвует ли пользователь в эксперименте;
  • назначает вариант по правилам и весам;
  • сохраняет назначение (sticky), чтобы вариант не "прыгал" между запросами;
  • читает winner-state через быстрый файловый кеш и хранит консистентно в БД.

Установка

composer require anbui/laravel-ab-experiments

После установки:

php artisan vendor:publish --provider="Anbui\LaravelABEx\LABExServiceProvider"
php artisan migrate

Использование

Ниже минимальный путь запуска:

  1. описать класс эксперимента;
  2. зарегистрировать класс в config/labex_conf.php;
  3. получить вариант через LABEx::forKey(...)->getVariant().

Минимально рабочий класс эксперимента:

<?php

declare(strict_types=1);

namespace App\AB;

use Anbui\LaravelABEx\Contracts\VariantRuleBuilderInterface;
use Anbui\LaravelABEx\Contracts\EligibilityRuleBuilderInterface;
use Anbui\LaravelABEx\Domain\Experiments\Experiment;
use Anbui\LaravelABEx\Domain\Variant\Rule\WeightedRule;

final class CheckoutExperiment extends Experiment
{
    public static function key(): string
    {
        return 'checkout_test';
    }

    public function variants(): array
    {
        return [
            'control',
            'variant_a',
            // можно добавить больше вариантов
        ];
    }

    public function defaultVariant(): string
    {
        return 'control';
    }

    public function eligibility(EligibilityRuleBuilderInterface $builder): void
    {    
        // В текущем API субъект задается строковым ключом forKey(...),
        // поэтому eligibility чаще всего задается вашими правилами по самому ключу.
    }

    public function definition(VariantRuleBuilderInterface $builder): void
    {
        $builder
            ->rule(new WeightedRule([
                'control' => 50,
                'variant_a' => 50,
            ]));
    }
}

Как принимается решение по пользователю

Порядок работы:

  1. Проверяется winner-state (если победитель зафиксирован, возвращается он).
  2. Если winner-state нет, проверяется sticky assignment.
  3. Если sticky assignment нет, проверяется eligibility (eligibility(...)).
  4. Если пользователь не прошел eligibility, возвращается defaultVariant().
  5. Если eligibility пройден, применяется definition(...) и выбирается вариант по правилам.

Сценарии:

  • если пользователь не проходит eligibility — он считается вне эксперимента и получает defaultVariant();
  • если проходит eligibility — пользователь участвует в эксперименте, и дальше выбирается вариант по правилам;
  • если у пользователя уже есть sticky assignment, eligibility повторно не проверяется, и возвращается закрепленный вариант.

Если пользователь подошел в эксперимент, но не подошел ни под одно правило:

  • возвращается defaultVariant();
  • пользователь остается участником эксперимента (isInExperiment() === true);
  • assignment сохраняется с rule_id = <ExperimentClass>::defaultVariant.

Важно: defaultVariant() должен возвращать одно из значений, перечисленных в variants().

Добавьте эксперимент в config/labex_conf.php:

'experiments' => [
    \App\AB\CheckoutExperiment::class,
],

Работа с API

Получить вариант:

use Anbui\LaravelABEx\Facades\LABEx;

$variant = LABEx::forKey('checkout_test', 'user:42')->getVariant();

if (LABEx::forKey('checkout_test', 'user:42')->isVariant('variant_a')) {
    // ...
}

if (LABEx::forKey('checkout_test', 'user:42')->isInExperiment()) {
    // пользователь участвует в эксперименте
}

Рекомендуемый паттерн в коде контроллера/сервиса:

$subjectKey = 'user:' . (string) $user->id;
$experiment = LABEx::forKey('checkout_test', $subjectKey);

if (!$experiment->isInExperiment()) {
    // пользователь не участвует в эксперименте
}

$variant = $experiment->getVariant();

Настройки пакета

Все настройки находятся в config/labex_conf.php.

Текущие доступные параметры:

  • experiments — список классов экспериментов. Ключ эксперимента берется из public static function key(): string в самом классе.
  • cache_path — директория, где хранится файловый кеш, в том числе winner-состояния.
  • database.table_prefix — префикс таблиц пакета в БД (например, labex_).

Пример:

return [
    'experiments' => [
        \App\AB\CheckoutExperiment::class,
    ],
    'cache_path' => storage_path('app/labex-cache'),
    'database' => [
        'table_prefix' => 'labex_',
    ],
];

Правила экспериментов

Описание доступных правил и примеры их использования:

На текущем этапе реализованы:

  • базовый API LABEx::forKey(...)->getVariant() и isVariant(...);
  • детерминированное распределение пользователя по вариантам;
  • sticky assignment в таблице labex_assignments;
  • winner-state в dual-store режиме: консистентное хранение в БД и быстрые чтения через файловый кеш.

Вклад в проект

Требования к разработке, проверкам и пул-реквестам описаны в CONTRIBUTING.md.