Skip to content

Targeting ​

Targeting decides who is eligible, never which variant: a subject outside the segment gets fallbackVariant with reason fallback_targeting_mismatch, and a subject inside it is bucketed exactly as if there were no rule. The context never enters the hash.

Context ​

Rules read an AssignmentContext passed to assign():

php
use Rasuvaeff\Yii3AbTesting\AssignmentContext;

$context = AssignmentContext::forEnvironment('production')
    ->withAttribute('plan', 'pro')
    ->withAttribute('country', 'DE');

$assignment = $ab->assign(
    experiment: 'checkout',
    subjectId: $userId,
    context: $context,
);

$ab->isWithContext(experiment: 'checkout', variant: 'green', subjectId: $userId, context: $context);

The context also travels into the Assignment, and from there into events — but only the attributes an AnalyticsContextPolicy allows reach storage; see Events v2.

Built-in rules ​

RuleTagMatches when
EnvironmentTargetingRuleenvironmentthe context environment is in the list
AttributeTargetingRuleattributegetAttribute($name) === $value (strict)
AndTargetingRuleandevery nested rule matches (short-circuit)
OrTargetingRuleorat least one nested rule matches (short-circuit)
php
use Rasuvaeff\Yii3AbTesting\AndTargetingRule;
use Rasuvaeff\Yii3AbTesting\AttributeTargetingRule;
use Rasuvaeff\Yii3AbTesting\EnvironmentTargetingRule;

new AndTargetingRule(rules: [
    new EnvironmentTargetingRule(environments: ['production']),
    new AttributeTargetingRule(attribute: 'plan', value: 'pro'),
]);

One representation for config and the database ​

ConfigExperimentProvider and DbExperimentProvider read the same tagged arrays, so a rule written in params can move to the targeting JSON column of the database package unchanged:

php
'targeting' => [
    'type' => 'and',
    'rules' => [
        ['type' => 'environment', 'values' => ['production']],
        ['type' => 'attribute', 'attribute' => 'plan', 'value' => 'pro'],
    ],
],

TargetingRuleCodecRegistry owns that format through decode() and encode(). To add a rule type, implement TargetingRuleCodec and pass it to the registry's constructor; custom codecs are consulted before the built-in one. Decoding rejects trees nested deeper than 64 levels.

Precedence ​

SituationResult
forcedVariant giventhe forced variant — targeting is not evaluated
Experiment disabledfallbackVariant, reason fallback_disabled
Rule does not matchfallbackVariant, reason fallback_targeting_mismatch
Rule matches, or no rulehash bucketing, reason assigned

Sticky stores follow the same order: forced, disabled and targeting decisions return before the store is read, so a stored pin never overrides the kill switch.