Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Rox Laravel Package

rollout/rox

rollout/rox is a Laravel package for managing feature rollouts and toggles. It helps you enable or disable features for specific users, segments, or rollout percentages, keeping release control in configuration and code.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and initialize once per process.

composer require rollout/rox

Look first at the repo README.md and src/Server/Rox.php — that is the public facade. The three classes you will spend 90% of your time with are Rox, RoxOptions, and the flag classes (RoxFlag, RoxInt, RoxString, RoxDouble).

Minimal boot:

use Rox\Server\Rox;
use Rox\Server\RoxOptions;

$options = new RoxOptions();
// storage + fetch interval + log level go here
Rox::setup('YOUR_APP_KEY', $options);

Rox::setUserContext(['id' => $user->id, 'email' => $user->email]);

$flag = Rox::getFlag('new-checkout');
if ($flag->isEnabled()) {
    // new path
}

Do this in your framework bootstrap (Laravel AppServiceProvider::boot, Symfony bundle boot, or a front-controller bootstrap.php) before any controller or middleware runs. Your first real use case should be a single percentage-rollout boolean flag wrapped in an if, not an experiment — get the plumbing proven before you trust it.

Notes: the package name is rollout/rox while the repo is rollout/rox-php. Composer metadata, license file, and PHP version constraints should be checked in composer.json before you commit; the license is marked NOASSERTION in the repo metadata, so confirm legal acceptability explicitly.

Implementation Patterns

Bootstrap singleton per request. PHP-FPM has no long-lived process, so Rox::setup() runs on every request. Keep it in one place and guard against double-initialization if your framework can boot twice (queues, tests, Octane/Swoole workers need special handling — see gotchas).

Storage adapter for cross-request persistence. The default in-memory storage loses the fetched configuration between requests, so every request re-fetches or falls back to defaults. Implement the package's storage interface backed by Redis, database, or your cache layer:

final class RedisRoxStorage implements RoxStorageInterface
{
    public function get(string $key) { return $this->redis->get("rox:$key"); }
    public function set(string $key, $value) { $this->redis->set("rox:$key", $value); }
}
$options->setStorage(new RedisRoxStorage($redis));

Context in middleware. Set the user context in a global middleware after the auth guard resolves the user, and consider Rox::freeze() right after to snapshot evaluations for the remainder of the request so a flag cannot flip mid-render.

public function handle($request, Closure $next)
{
    Rox::setUserContext(['id' => (string) $request->user()->id]);
    Rox::freeze();
    return $next($request);
}

Remember to unfreeze (Rox unfreeze/reset equivalent) if you share a process across users (Octane, Swoole, queue workers).

Typed flags, not casts. Ask for the type you need and always pass a default at the call site so the code still behaves when Rox is unreachable:

$limit = Rox::getInt('page-size', 25)->getValue();
$title = Rox::getString('hero-title', 'Welcome')->getValue();

Container / service provider. Wrap the facade in your own FeatureFlags interface with isEnabled(string $key, bool $default): bool methods. This keeps Roc calls out of controllers, makes flags mockable in tests, and — critically for this package — lets you swap the SDK later without touching business code.

Testing. Register a test container / memory container returning deterministic roxy values, or subclass your wrapper with an in-memory map. Never hit the Rox backend in CI; assert both the "on" and "off" branches and default-value behavior.

Experiments and dynamic config. Use flag values as variant selectors, log exposure yourself (the SDK will not do product analytics for you), and pull dynamic configuration through the same wrapper so a backend outage degrades to hard-coded defaults.

Gotchas and Tips

  • Setup ordering. Calling Rox::getFlag() before Rox::setup() will fail or silently return defaults; there is no lazy init. Establish init in bootstrap and assert it in a smoke test.
  • First-request cold start. Fetching configuration is asynchronous; the very first requests after a deploy will evaluate against defaults. Make defaults safe and feature-flag-code tolerant of "unknown".
  • freeze() is per-process, not per-request in any shared-runtime environment. If you run Octane/Swoole or long-lived queue workers, freeze/unfreeze around the unit of work or you will leak one user's flags to the next.
  • In-memory storage is a trap in classic PHP. Without an external storage adapter you effectively re-fetch per request; monitor fetch latency and error rates and set generous defaults.
  • Swallow exceptions deliberately. SDKs like this often catch network errors for performance; verify behavior in RoxOptions and log at a level you can actually see when debugging. Turn on verbose logging temporarily to dump the fetched roxy/configuration.
  • Fetch interval vs. TTL. Tune the fetch interval in RoxOptions; too aggressive hammers the backend, too lazy delays kill-switch propagation. For an incident kill switch, know your worst-case delay and have an env-var override path independent of Rox.
  • Composer/license hygiene. License is NOASSERTION; last release January 2024, zero stars, zero dependents. Treat this as a low-maintenance dependency: pin the version, vendor the source if necessary, and do not build load-bearing architecture on undocumented behavior.
  • Escape hatch. Because adoption and maintenance signal are weak, keep the wrapper interface thin (2–3 methods). Migrating to LaunchDarkly, Unleash, or a homegrown config table should be a one-class change.
  • Debugging checklist: (1) confirm setup ran once, (2) confirm user context is populated before flag reads, (3) confirm storage is shared across requests, (4) inspect the raw fetched configuration, (5) reproduce with defaults to see if the issue is SDK or flag config.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo