Skip to main content
WestyxNexus\OpenFeature\NexusProvider lets you use Westyx Nexus as an OpenFeature provider in PHP applications. It wraps an already-initialized NexusClient. Config values - string, number and object - are served from the client’s in-memory snapshot with no network call. Boolean flags are served from the snapshot too, unless the EvaluationContext carries a targeting key: then the flag is evaluated for that identity through the AB Testing add-on. See Per-user targeting.

Installation

The provider ships inside the westyx/nexus package, alongside the Laravel service provider. Install the OpenFeature SDK with it:
open-feature/sdk is a Composer suggest rather than a dependency, so a project that does not use the provider installs nothing extra - PHP only loads the class if you reference it. Requires: PHP 8.3+, open-feature/sdk ^2.1, westyx/nexus >=0.12.0.
In v0.11.0 and earlier the provider was a separate westyx/nexus-openfeature sub-package, which had no installable release: a Composer package must sit at the root of its own git repository, so a sub-directory package cannot be registered by Packagist or by a GitLab Composer registry. If you vendored the file directly, the class is now WestyxNexus\OpenFeature\NexusProvider.

Usage

Per-user targeting

Pass a targeting key and the flag is evaluated for that identity instead of returning the anonymous snapshot value:
Requires the AB Testing add-on on the project. Without it the provider serves the snapshot value and reports STATIC - the correct answer for a project with no per-user rules to apply - and stops calling the endpoint for five minutes. The throttle expires on its own, so activating the add-on takes effect with nothing to restart.

One request per identity, not per flag

The first targeted evaluation asks about every flag in the snapshot at once and memoises the answers, so the remaining evaluations for that identity are served from memory. A page resolving twenty flags for a user makes one call, not twenty. A flag set larger than the endpoint’s 200-key limit is split across requests automatically. A flag the snapshot does not define is never sent: the endpoint answers false for a key it does not know, which is indistinguishable from “the flag exists and is off”, so sending it would override your true default while reporting a successful evaluation.

Reasons

Switch on the reason rather than on the value alone - it tells you what kind of answer you received.

Attributes are strings

Cohort conditions compare attribute values as strings (eq, neq, in), so a non-string context attribute is dropped and logged, never converted. No conversion is lossless - an integer above 253 does not survive a float, and an array has no form the matcher accepts - and a coerced value that then matches no rule is harder to diagnose than an absent one. Pass the value in the form your cohort rule matches. The targeting key travels as the identity and is not repeated as an attribute.
A targeted boolean evaluation performs I/O on a memo miss. resolveBooleanValue is synchronous, so the calling code blocks for the duration of one HTTP request. If a code path must not block, pass no targeting key - or call NexusClient::evaluateAb() directly, where the call is explicit.

Tuning

Every value is validated when the options are constructed, and the failure names the option and the value. Eviction takes expired entries first, then the entry closest to expiring. On the lifetime of the memo. Under PHP-FPM each request is its own process, so the provider - and the memo - live for one request. The TTL and the cap therefore bound a single request’s evaluations, and the batching is where the benefit is. In a CLI daemon or a queue worker, where the process outlives the work item, the TTL applies as written.

Evaluation behavior

Types are not coerced. A config holding the string "8080" resolves as TYPE_MISMATCH on getIntegerValue, not as the number 8080, and 2.9 does not resolve as 2 - rounding it while reporting a successful resolution would hand you a wrong number with nothing to indicate it. A whole-numbered float such as 5.0 does resolve as the integer 5, because JSON has a single number type. variant is the string form of the resolved value for scalar types - lowercase 'true' / 'false' for booleans - and absent on an object resolution, which has no short identifier to name.

Diagnostics

The provider uses the logger from the OpenFeature SDK’s LoggerAwareTrait, so it takes no logger option of its own:
A dropped context attribute is reported at debug level with the attribute name and its type; a failed targeted evaluation at warning level. Client diagnostics - sync, streaming, WIF - go to NexusConfig::$logger; see Custom logging.