Skip to content

Commit

Permalink
Merge bc3bb03 into e46fde5
Browse files Browse the repository at this point in the history
  • Loading branch information
mnoman09 committed Oct 29, 2021
2 parents e46fde5 + bc3bb03 commit 6f03ff5
Show file tree
Hide file tree
Showing 11 changed files with 1,443 additions and 150 deletions.
66 changes: 66 additions & 0 deletions src/Optimizely/Config/DatafileProjectConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,13 @@ class DatafileProjectConfig implements ProjectConfigInterface
*/
private $_sendFlagDecisions;

/**
* Map indicating variations of flag decisions
*
* @return map
*/
private $_flagVariationsMap;

/**
* DatafileProjectConfig constructor to load and set project configuration data.
*
Expand Down Expand Up @@ -376,7 +383,24 @@ public function __construct($datafile, $logger, $errorHandler)
}
}
}
$this->_flagVariationsMap = array();
foreach ($this->_featureFlags as $flag) {
$flagVariations = array();
$flagRules = $this->getAllRulesForFlag($flag);

foreach ($flagRules as $rule) {
$flagVariations = array_merge($flagVariations, array_filter(array_values($rule->getVariations()), function ($variation) use ($flagVariations) {
foreach ($flagVariations as $flagVariation) {
if ($flagVariation->getId() == $variation->getId()) {
return false;
}
}
return true;
}));
}

$this->_flagVariationsMap[$flag->getKey()] = $flagVariations;
}
// Add variations for rollout experiments to variationIdMap and variationKeyMap
$this->_variationIdMap = $this->_variationIdMap + $rolloutVariationIdMap;
$this->_variationKeyMap = $this->_variationKeyMap + $rolloutVariationKeyMap;
Expand Down Expand Up @@ -404,6 +428,18 @@ public function __construct($datafile, $logger, $errorHandler)
}
}

private function getAllRulesForFlag(FeatureFlag $flag)
{
$rules = array();
foreach ($flag->getExperimentIds() as $experimentId) {
array_push($rules, $this->_experimentIdMap[$experimentId]);
}
if ($this->_rolloutIdMap && key_exists($flag->getRolloutId(), $this->_rolloutIdMap)) {
$rollout = $this->_rolloutIdMap[$flag->getRolloutId()];
$rules = array_merge($rules, $rollout->getExperiments());
}
return $rules;
}
/**
* Create ProjectConfig based on datafile string.
*
Expand Down Expand Up @@ -614,6 +650,26 @@ public function getExperimentFromId($experimentId)
return new Experiment();
}

/**
* Gets the variation associated with experiment or rollout in instance of given feature flag key
*
* @param string Feature flag key
* @param string variation key
*
* @return Variation / null
*/
public function getFlagVariationByKey($flagKey, $variationKey)
{
if (array_key_exists($flagKey, $this->_flagVariationsMap)) {
foreach ($this->_flagVariationsMap[$flagKey] as $variation) {
if ($variation->getKey() == $variationKey) {
return $variation;
}
}
}
return null;
}

/**
* @param String $featureKey Key of the feature flag
*
Expand Down Expand Up @@ -868,6 +924,16 @@ public function isFeatureExperiment($experimentId)
return array_key_exists($experimentId, $this->_experimentFeatureMap);
}

/**
* Returns map array of Flag key as key and Variations as value
*
* @return array
*/
public function getFlagVariationsMap()
{
return $this->_flagVariationsMap;
}

/**
* Returns if flag decisions should be sent to server or not
*
Expand Down
18 changes: 17 additions & 1 deletion src/Optimizely/Config/ProjectConfigInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,23 @@ public function getVariationFromKeyByExperimentId($experimentId, $variationKey);
* @return FeatureVariable / null
*/
public function getFeatureVariableFromKey($featureFlagKey, $variableKey);


/**
* Gets the variation associated with experiment or rollout in instance of given feature flag key
*
* @param string Feature flag key
* @param string variation key
*
* @return Variation / null
*/
public function getFlagVariationByKey($flagKey, $variationKey);

/**
* Returns map array of Flag key as key and Variations as value
*
* @return array
*/
public function getFlagVariationsMap();
/**
* Determines if given experiment is a feature test.
*
Expand Down
171 changes: 111 additions & 60 deletions src/Optimizely/DecisionService/DecisionService.php

Large diffs are not rendered by default.

26 changes: 21 additions & 5 deletions src/Optimizely/Event/Builder/EventBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use Optimizely\Utils\EventTagUtils;
use Optimizely\Utils\GeneratorUtils;
use Optimizely\Utils\Validator;
use phpDocumentor\Reflection\Types\This;

class EventBuilder
{
Expand Down Expand Up @@ -139,18 +140,28 @@ private function getCommonParams($config, $userId, $attributes)
* Helper function to get parameters specific to impression event.
*
* @param $experiment Experiment Experiment being activated.
* @param $variationId String ID representing the variation for the user.
* @param $variation Variation representing the variation for the user is allocated.
* @param $flagKey string feature flag key.
* @param $ruleKey string feature or rollout experiment key.
* @param $ruleType string feature or rollout experiment source type.
* @param $enabled Boolean feature enabled.
*
* @return array Hash representing parameters particular to impression event.
*/
private function getImpressionParams(Experiment $experiment, $variation, $flagKey, $ruleKey, $ruleType, $enabled)
{
$variationKey = $variation->getKey() ? $variation->getKey() : '';
$experimentID = '';
$campaignID = '';
if ($experiment->getId()) {
$experimentID = $experiment->getId();
$campaignID = $experiment->getLayerId();
}
$impressionParams = [
DECISIONS => [
[
CAMPAIGN_ID => $experiment->getLayerId(),
EXPERIMENT_ID => $experiment->getId(),
CAMPAIGN_ID => $campaignID,
EXPERIMENT_ID => $experimentID,
VARIATION_ID => $variation->getId(),
METADATA => [
FLAG_KEY => $flagKey,
Expand Down Expand Up @@ -232,9 +243,14 @@ private function getConversionParams($eventEntity, $eventTags)
public function createImpressionEvent($config, $experimentId, $variationKey, $flagKey, $ruleKey, $ruleType, $enabled, $userId, $attributes)
{
$eventParams = $this->getCommonParams($config, $userId, $attributes);

$experiment = $config->getExperimentFromId($experimentId);
$variation = $config->getVariationFromKeyByExperimentId($experimentId, $variationKey);

if (empty($experimentId)) {
$variation = $config->getFlagVariationByKey($flagKey, $variationKey);
} else {
$variation = $config->getVariationFromKeyByExperimentId($experimentId, $variationKey);
}

$impressionParams = $this->getImpressionParams($experiment, $variation, $flagKey, $ruleKey, $ruleType, $enabled);

$eventParams[VISITORS][0][SNAPSHOTS][] = $impressionParams;
Expand Down
73 changes: 55 additions & 18 deletions src/Optimizely/Optimizely.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use Optimizely\Decide\OptimizelyDecisionMessage;
use Optimizely\DecisionService\DecisionService;
use Optimizely\DecisionService\FeatureDecision;
use Optimizely\OptimizelyDecisionContext;
use Optimizely\Entity\Experiment;
use Optimizely\Entity\FeatureVariable;
use Optimizely\Enums\DecisionNotificationTypes;
Expand Down Expand Up @@ -201,11 +202,15 @@ private function validateUserInputs($attributes, $eventTags = null)
}

/**
* @param DatafileProjectConfig DatafileProjectConfig instance
* @param string Experiment ID
* @param string Variation key
* @param string Flag key
* @param string Rule key
* @param string Rule type
* @param boolean Feature enabled
* @param string User ID
* @param array Associative array of user attributes
* @param DatafileProjectConfig DatafileProjectConfig instance
*/
protected function sendImpressionEvent($config, $experimentId, $variationKey, $flagKey, $ruleKey, $ruleType, $enabled, $userId, $attributes)
{
Expand Down Expand Up @@ -347,22 +352,32 @@ public function decide(OptimizelyUserContext $userContext, $key, array $decideOp
$decisionEventDispatched = false;

// get decision
$decision = $this->_decisionService->getVariationForFeature(
$config,
$featureFlag,
$userId,
$userAttributes,
$decideOptions
);

$decideReasons = $decision->getReasons();
$decision = null;
// check forced-decisions first
$context = new OptimizelyDecisionContext($flagKey, $ruleKey);
list($forcedDecisionResponse, $reasons) = $userContext->findValidatedForcedDecision($context);
if ($forcedDecisionResponse) {
$decision = new FeatureDecision(null, $forcedDecisionResponse, FeatureDecision::DECISION_SOURCE_FEATURE_TEST, $decideReasons);
} else {
// regular decision
$decision = $this->_decisionService->getVariationForFeature(
$config,
$featureFlag,
$userContext,
$decideOptions
);
}
$decideReasons = array_merge($decideReasons, $reasons);
$decideReasons = array_merge($decideReasons, $decision->getReasons());
$variation = $decision->getVariation();

if ($variation) {
$variationKey = $variation->getKey();
$featureEnabled = $variation->getFeatureEnabled();
$ruleKey = $decision->getExperiment()->getKey();
$experimentId = $decision->getExperiment()->getId();
if ($decision->getExperiment()) {
$ruleKey = $decision->getExperiment()->getKey();
$experimentId = $decision->getExperiment()->getId();
}
} else {
$variationKey = null;
$ruleKey = null;
Expand Down Expand Up @@ -687,7 +702,8 @@ public function getVariation($experimentKey, $userId, $attributes = null)
return null;
}

list($variation, $reasons) = $this->_decisionService->getVariation($config, $experiment, $userId, $attributes);
$userContext = $this->createUserContext($userId, $attributes ? $attributes : []);
list($variation, $reasons) = $this->_decisionService->getVariation($config, $experiment, $userContext);
$variationKey = ($variation === null) ? null : $variation->getKey();

if ($config->isFeatureExperiment($experiment->getId())) {
Expand Down Expand Up @@ -815,7 +831,8 @@ public function isFeatureEnabled($featureFlagKey, $userId, $attributes = null)
}

$featureEnabled = false;
$decision = $this->_decisionService->getVariationForFeature($config, $featureFlag, $userId, $attributes);
$userContext = $this->createUserContext($userId, $attributes?: []);
$decision = $this->_decisionService->getVariationForFeature($config, $featureFlag, $userContext);
$variation = $decision->getVariation();

if ($config->getSendFlagDecisions() && ($decision->getSource() == FeatureDecision::DECISION_SOURCE_ROLLOUT || !$variation)) {
Expand Down Expand Up @@ -948,8 +965,8 @@ public function getFeatureVariableValueForType(
// Error logged in DatafileProjectConfig - getFeatureFlagFromKey
return null;
}

$decision = $this->_decisionService->getVariationForFeature($config, $featureFlag, $userId, $attributes);
$userContext = $this->createUserContext($userId, $attributes? $attributes : []);
$decision = $this->_decisionService->getVariationForFeature($config, $featureFlag, $userContext);
$variation = $decision->getVariation();
$experiment = $decision->getExperiment();
$featureEnabled = $variation !== null ? $variation->getFeatureEnabled() : false;
Expand Down Expand Up @@ -1124,7 +1141,7 @@ public function getAllFeatureVariables($featureFlagKey, $userId, $attributes = n
return null;
}

$decision = $this->_decisionService->getVariationForFeature($config, $featureFlag, $userId, $attributes);
$decision = $this->_decisionService->getVariationForFeature($config, $featureFlag, $this->createUserContext($userId, $attributes));
$variation = $decision->getVariation();
$experiment = $decision->getExperiment();
$featureEnabled = $variation !== null ? $variation->getFeatureEnabled() : false;
Expand Down Expand Up @@ -1247,7 +1264,14 @@ private function getFeatureVariableValueFromVariation($featureFlagKey, $variable
*/
public function isValid()
{
return $this->getConfig() !== null;
if (!$this->getConfig()) {
$this->_logger->log(
Logger::ERROR,
"Optimizely SDK not configured properly yet."
);
return false;
}
return true;
}

/**
Expand Down Expand Up @@ -1281,4 +1305,17 @@ protected function validateInputs(array $values, $logLevel = Logger::ERROR)

return $isValid;
}

/**
* Gets the variation associated with experiment or rollout in instance of given feature flag key
*
* @param string Feature flag key
* @param string variation key
*
* @return Variation / null
*/
public function getFlagVariationByKey($flagKey, $variationKey)
{
return $this->getConfig()->getFlagVariationByKey($flagKey, $variationKey);
}
}

0 comments on commit 6f03ff5

Please sign in to comment.