|
18 | 18 |
|
19 | 19 | use Exception; |
20 | 20 | use Optimizely\Config\DatafileProjectConfig; |
| 21 | +use Optimizely\Entity\Variation; |
21 | 22 | use Optimizely\Exceptions\InvalidAttributeException; |
22 | 23 | use Optimizely\Exceptions\InvalidEventTagException; |
23 | 24 | use Throwable; |
@@ -292,7 +293,7 @@ public function getOptimizelyConfig() |
292 | 293 | } |
293 | 294 |
|
294 | 295 | $optConfigService = new OptimizelyConfigService($config); |
295 | | - |
| 296 | + |
296 | 297 | return $optConfigService->getConfig(); |
297 | 298 | } |
298 | 299 |
|
@@ -633,15 +634,18 @@ public function getEnabledFeatures($userId, $attributes = null) |
633 | 634 | } |
634 | 635 |
|
635 | 636 | /** |
636 | | - * Get the string value of the specified variable in the feature flag. |
| 637 | + * Get value of the specified variable in the feature flag. |
637 | 638 | * |
638 | 639 | * @param string Feature flag key |
639 | 640 | * @param string Variable key |
640 | 641 | * @param string User ID |
641 | 642 | * @param array Associative array of user attributes |
642 | 643 | * @param string Variable type |
643 | 644 | * |
644 | | - * @return string Feature variable value / null |
| 645 | + * @return string|boolean|number|array|null Value of the variable cast to the appropriate |
| 646 | + * type, or null if the feature key is invalid, the |
| 647 | + * variable key is invalid, or there is a mismatch |
| 648 | + * with the type of the variable |
645 | 649 | */ |
646 | 650 | public function getFeatureVariableValueForType( |
647 | 651 | $featureFlagKey, |
@@ -673,69 +677,20 @@ public function getFeatureVariableValueForType( |
673 | 677 | return null; |
674 | 678 | } |
675 | 679 |
|
676 | | - $variable = $config->getFeatureVariableFromKey($featureFlagKey, $variableKey); |
677 | | - if (!$variable) { |
678 | | - // Error message logged in ProjectConfigInterface- getFeatureVariableFromKey |
679 | | - return null; |
680 | | - } |
681 | | - |
682 | | - if ($variableType != $variable->getType()) { |
683 | | - $this->_logger->log( |
684 | | - Logger::ERROR, |
685 | | - "Variable is of type '{$variable->getType()}', but you requested it as type '{$variableType}'." |
686 | | - ); |
| 680 | + $decision = $this->_decisionService->getVariationForFeature($config, $featureFlag, $userId, $attributes); |
| 681 | + $variation = $decision->getVariation(); |
| 682 | + $experiment = $decision->getExperiment(); |
| 683 | + $featureEnabled = $variation !== null ? $variation->getFeatureEnabled() : false; |
| 684 | + $variableValue = $this->getFeatureVariableValueFromVariation($featureFlagKey, $variableKey, $variableType, $featureEnabled, $variation, $userId); |
| 685 | + // returning as variable not found or type is invalid |
| 686 | + if ($variableValue === null) { |
687 | 687 | return null; |
688 | 688 | } |
689 | | - |
690 | | - $featureEnabled = false; |
691 | | - $decision = $this->_decisionService->getVariationForFeature($config, $featureFlag, $userId, $attributes); |
692 | | - $variableValue = $variable->getDefaultValue(); |
693 | | - |
694 | | - if ($decision->getVariation() === null) { |
695 | | - $this->_logger->log( |
696 | | - Logger::INFO, |
697 | | - "User '{$userId}'is not in any variation, ". |
698 | | - "returning default value '{$variableValue}'." |
| 689 | + if ($variation && $decision->getSource() == FeatureDecision::DECISION_SOURCE_FEATURE_TEST) { |
| 690 | + $sourceInfo = (object) array( |
| 691 | + 'experimentKey'=> $experiment->getKey(), |
| 692 | + 'variationKey'=> $variation->getKey() |
699 | 693 | ); |
700 | | - } else { |
701 | | - $experiment = $decision->getExperiment(); |
702 | | - $variation = $decision->getVariation(); |
703 | | - $featureEnabled = $variation->getFeatureEnabled(); |
704 | | - |
705 | | - if ($decision->getSource() == FeatureDecision::DECISION_SOURCE_FEATURE_TEST) { |
706 | | - $sourceInfo = (object) array( |
707 | | - 'experimentKey'=> $experiment->getKey(), |
708 | | - 'variationKey'=> $variation->getKey() |
709 | | - ); |
710 | | - } |
711 | | - |
712 | | - if ($featureEnabled) { |
713 | | - $variableUsage = $variation->getVariableUsageById($variable->getId()); |
714 | | - if ($variableUsage) { |
715 | | - $variableValue = $variableUsage->getValue(); |
716 | | - $this->_logger->log( |
717 | | - Logger::INFO, |
718 | | - "Returning variable value '{$variableValue}' for variation '{$variation->getKey()}' ". |
719 | | - "of feature flag '{$featureFlagKey}'" |
720 | | - ); |
721 | | - } else { |
722 | | - $this->_logger->log( |
723 | | - Logger::INFO, |
724 | | - "Variable '{$variableKey}' is not used in variation '{$variation->getKey()}', ". |
725 | | - "returning default value '{$variableValue}'." |
726 | | - ); |
727 | | - } |
728 | | - } else { |
729 | | - $this->_logger->log( |
730 | | - Logger::INFO, |
731 | | - "Feature '{$featureFlagKey}' for variation '{$variation->getKey()}' is not enabled, ". |
732 | | - "returning default value '{$variableValue}'." |
733 | | - ); |
734 | | - } |
735 | | - } |
736 | | - |
737 | | - if (!is_null($variableValue)) { |
738 | | - $variableValue = VariableTypeUtils::castStringToType($variableValue, $variableType, $this->_logger); |
739 | 694 | } |
740 | 695 |
|
741 | 696 | $attributes = $attributes ?: []; |
@@ -844,6 +799,173 @@ public function getFeatureVariableString($featureFlagKey, $variableKey, $userId, |
844 | 799 | ); |
845 | 800 | } |
846 | 801 |
|
| 802 | + /** |
| 803 | + * Get the JSON value of the specified variable in the feature flag. |
| 804 | + * |
| 805 | + * @param string Feature flag key |
| 806 | + * @param string Variable key |
| 807 | + * @param string User ID |
| 808 | + * @param array Associative array of user attributes |
| 809 | + * |
| 810 | + * @return array Associative array of json variable including key and value |
| 811 | + */ |
| 812 | + public function getFeatureVariableJson($featureFlagKey, $variableKey, $userId, $attributes = null) |
| 813 | + { |
| 814 | + return $this->getFeatureVariableValueForType( |
| 815 | + $featureFlagKey, |
| 816 | + $variableKey, |
| 817 | + $userId, |
| 818 | + $attributes, |
| 819 | + FeatureVariable::JSON_TYPE |
| 820 | + ); |
| 821 | + } |
| 822 | + |
| 823 | + /** |
| 824 | + * Returns values for all the variables attached to the given feature |
| 825 | + * |
| 826 | + * @param string Feature flag key |
| 827 | + * @param string User ID |
| 828 | + * @param array Associative array of user attributes |
| 829 | + * |
| 830 | + * @return array|null array of all the variables, or null if the feature key is invalid |
| 831 | + */ |
| 832 | + public function getAllFeatureVariables($featureFlagKey, $userId, $attributes = null) |
| 833 | + { |
| 834 | + $config = $this->getConfig(); |
| 835 | + if ($config === null) { |
| 836 | + $this->_logger->log(Logger::ERROR, sprintf(Errors::INVALID_DATAFILE, __FUNCTION__)); |
| 837 | + return null; |
| 838 | + } |
| 839 | + |
| 840 | + if (!$this->validateInputs( |
| 841 | + [ |
| 842 | + self::FEATURE_FLAG_KEY => $featureFlagKey, |
| 843 | + self::USER_ID => $userId |
| 844 | + ] |
| 845 | + ) |
| 846 | + ) { |
| 847 | + return null; |
| 848 | + } |
| 849 | + |
| 850 | + $featureFlag = $config->getFeatureFlagFromKey($featureFlagKey); |
| 851 | + if ($featureFlag && (!$featureFlag->getId())) { |
| 852 | + return null; |
| 853 | + } |
| 854 | + |
| 855 | + $decision = $this->_decisionService->getVariationForFeature($config, $featureFlag, $userId, $attributes); |
| 856 | + $variation = $decision->getVariation(); |
| 857 | + $experiment = $decision->getExperiment(); |
| 858 | + $featureEnabled = $variation !== null ? $variation->getFeatureEnabled() : false; |
| 859 | + |
| 860 | + $allVariables = []; |
| 861 | + foreach ($featureFlag->getVariables() as $variable) { |
| 862 | + $allVariables[$variable->getKey()] = $this->getFeatureVariableValueFromVariation( |
| 863 | + $featureFlagKey, |
| 864 | + $variable->getKey(), |
| 865 | + null, |
| 866 | + $featureEnabled, |
| 867 | + $variation, |
| 868 | + $userId |
| 869 | + ); |
| 870 | + } |
| 871 | + |
| 872 | + $sourceInfo = (object) array(); |
| 873 | + if ($variation && $decision->getSource() == FeatureDecision::DECISION_SOURCE_FEATURE_TEST) { |
| 874 | + $sourceInfo = (object) array( |
| 875 | + 'experimentKey'=> $experiment->getKey(), |
| 876 | + 'variationKey'=> $variation->getKey() |
| 877 | + ); |
| 878 | + } |
| 879 | + |
| 880 | + $attributes = $attributes ?: []; |
| 881 | + |
| 882 | + $this->notificationCenter->sendNotifications( |
| 883 | + NotificationType::DECISION, |
| 884 | + array( |
| 885 | + DecisionNotificationTypes::ALL_FEATURE_VARIABLES, |
| 886 | + $userId, |
| 887 | + $attributes, |
| 888 | + (object)array( |
| 889 | + 'featureKey' => $featureFlagKey, |
| 890 | + 'featureEnabled' => $featureEnabled, |
| 891 | + 'variableValues' => $allVariables, |
| 892 | + 'source' => $decision->getSource(), |
| 893 | + 'sourceInfo' => $sourceInfo |
| 894 | + ) |
| 895 | + ) |
| 896 | + ); |
| 897 | + |
| 898 | + return $allVariables; |
| 899 | + } |
| 900 | + |
| 901 | + /** |
| 902 | + * Get the value of the specified variable on the basis of its status and usage |
| 903 | + * |
| 904 | + * @param string Feature flag key |
| 905 | + * @param string Variable key |
| 906 | + * @param boolean Feature Status |
| 907 | + * @param Variation for feature |
| 908 | + * @param string User Id |
| 909 | + * |
| 910 | + * @return string|boolean|number|array|null Value of the variable cast to the appropriate |
| 911 | + * type, or null if the feature key is invalid, the |
| 912 | + * variable key is invalid, or there is a mismatch |
| 913 | + * with the type of the variable |
| 914 | + */ |
| 915 | + private function getFeatureVariableValueFromVariation($featureFlagKey, $variableKey, $variableType, $featureEnabled, $variation, $userId) |
| 916 | + { |
| 917 | + $config = $this->getConfig(); |
| 918 | + $variable = $config->getFeatureVariableFromKey($featureFlagKey, $variableKey); |
| 919 | + if (!$variable) { |
| 920 | + // Error message logged in ProjectConfigInterface- getFeatureVariableFromKey |
| 921 | + return null; |
| 922 | + } |
| 923 | + if ($variableType && $variableType != $variable->getType()) { |
| 924 | + $this->_logger->log( |
| 925 | + Logger::ERROR, |
| 926 | + "Variable is of type '{$variable->getType()}', but you requested it as type '{$variableType}'." |
| 927 | + ); |
| 928 | + return null; |
| 929 | + } |
| 930 | + $variableValue = $variable->getDefaultValue(); |
| 931 | + if ($variation === null) { |
| 932 | + $this->_logger->log( |
| 933 | + Logger::INFO, |
| 934 | + "User '{$userId}'is not in any variation, ". |
| 935 | + "returning default value '{$variableValue}'." |
| 936 | + ); |
| 937 | + } else { |
| 938 | + if ($featureEnabled) { |
| 939 | + $variableUsage = $variation->getVariableUsageById($variable->getId()); |
| 940 | + if ($variableUsage) { |
| 941 | + $variableValue = $variableUsage->getValue(); |
| 942 | + $this->_logger->log( |
| 943 | + Logger::INFO, |
| 944 | + "Returning variable value '{$variableValue}' for variation '{$variation->getKey()}' ". |
| 945 | + "of feature flag '{$featureFlagKey}'" |
| 946 | + ); |
| 947 | + } else { |
| 948 | + $this->_logger->log( |
| 949 | + Logger::INFO, |
| 950 | + "Variable '{$variableKey}' is not used in variation '{$variation->getKey()}', ". |
| 951 | + "returning default value '{$variableValue}'." |
| 952 | + ); |
| 953 | + } |
| 954 | + } else { |
| 955 | + $this->_logger->log( |
| 956 | + Logger::INFO, |
| 957 | + "Feature '{$featureFlagKey}' for variation '{$variation->getKey()}' is not enabled, ". |
| 958 | + "returning default value '{$variableValue}'." |
| 959 | + ); |
| 960 | + } |
| 961 | + } |
| 962 | + |
| 963 | + if (!is_null($variableValue)) { |
| 964 | + $variableValue = VariableTypeUtils::castStringToType($variableValue, $variable->getType(), $this->_logger); |
| 965 | + } |
| 966 | + return $variableValue; |
| 967 | + } |
| 968 | + |
847 | 969 | /** |
848 | 970 | * Determine if the instance of the Optimizely client is valid. |
849 | 971 | * An instance can be deemed invalid if it was not initialized |
|
0 commit comments