├── .coveralls.yml ├── .devcontainer └── devcontainer.json ├── .github ├── ISSUE_TEMPLATE │ ├── BUG-REPORT.yml │ ├── ENHANCEMENT.yml │ ├── FEATURE-REQUEST.md │ └── config.yml ├── pull_request_template.md └── workflows │ ├── integration_test.yml │ ├── php.yml │ └── ticket_reference_check.yml ├── .gitignore ├── CHANGELOG.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bug-bash ├── Decide.php ├── DecideAll.php ├── DecideForKeys.php ├── ForcedDecision.php ├── OptiConfig.php ├── TrackEvent.php └── _bug-bash-autoload.php ├── composer.json ├── composer.lock ├── phpcs.xml ├── phpunit.xml ├── phpunit_bootstrap.php ├── src └── Optimizely │ ├── Bucketer.php │ ├── Config │ ├── DatafileProjectConfig.php │ └── ProjectConfigInterface.php │ ├── Decide │ ├── OptimizelyDecideOption.php │ ├── OptimizelyDecision.php │ └── OptimizelyDecisionMessage.php │ ├── DecisionService │ ├── DecisionService.php │ └── FeatureDecision.php │ ├── Entity │ ├── Attribute.php │ ├── Audience.php │ ├── Event.php │ ├── Experiment.php │ ├── FeatureFlag.php │ ├── FeatureVariable.php │ ├── Group.php │ ├── Rollout.php │ ├── TrafficAllocation.php │ ├── VariableUsage.php │ └── Variation.php │ ├── Enums │ ├── CommonAudienceEvaluationLogs.php │ ├── ControlAttributes.php │ ├── DecisionNotificationTypes.php │ ├── ExperimentAudienceEvaluationLogs.php │ ├── ProjectConfigManagerConstants.php │ └── RolloutAudienceEvaluationLogs.php │ ├── ErrorHandler │ ├── DefaultErrorHandler.php │ ├── ErrorHandlerInterface.php │ └── NoOpErrorHandler.php │ ├── Event │ ├── Builder │ │ ├── EventBuilder.php │ │ └── Params.php │ ├── Dispatcher │ │ ├── DefaultEventDispatcher.php │ │ └── EventDispatcherInterface.php │ └── LogEvent.php │ ├── Exceptions │ ├── InvalidAttributeException.php │ ├── InvalidAudienceException.php │ ├── InvalidCallbackArgumentCountException.php │ ├── InvalidDatafileVersionException.php │ ├── InvalidEventException.php │ ├── InvalidEventTagException.php │ ├── InvalidExperimentException.php │ ├── InvalidFeatureFlagException.php │ ├── InvalidFeatureVariableException.php │ ├── InvalidGroupException.php │ ├── InvalidInputException.php │ ├── InvalidNotificationTypeException.php │ ├── InvalidRolloutException.php │ ├── InvalidVariationException.php │ └── OptimizelyException.php │ ├── Logger │ ├── DefaultLogger.php │ ├── LoggerInterface.php │ └── NoOpLogger.php │ ├── Notification │ ├── NotificationCenter.php │ └── NotificationType.php │ ├── Optimizely.php │ ├── OptimizelyConfig │ ├── OptimizelyAttribute.php │ ├── OptimizelyAudience.php │ ├── OptimizelyConfig.php │ ├── OptimizelyConfigService.php │ ├── OptimizelyEvent.php │ ├── OptimizelyExperiment.php │ ├── OptimizelyFeature.php │ ├── OptimizelyVariable.php │ └── OptimizelyVariation.php │ ├── OptimizelyFactory.php │ ├── OptimizelyUserContext.php │ ├── ProjectConfigManager │ ├── HTTPProjectConfigManager.php │ ├── ProjectConfigManagerInterface.php │ └── StaticProjectConfigManager.php │ ├── UserProfile │ ├── Decision.php │ ├── UserProfile.php │ ├── UserProfileServiceInterface.php │ └── UserProfileUtils.php │ └── Utils │ ├── ConditionTreeEvaluator.php │ ├── ConfigParser.php │ ├── CustomAttributeConditionEvaluator.php │ ├── Errors.php │ ├── EventTagUtils.php │ ├── GeneratorUtils.php │ ├── SemVersionConditionEvaluator.php │ ├── Validator.php │ ├── VariableTypeUtils.php │ └── schema.json └── tests ├── BucketerTest.php ├── ConfigTests └── DatafileProjectConfigTest.php ├── DecisionServiceTests └── DecisionServiceTest.php ├── ErrorHandlerTests ├── DefaultErrorHandlerTest.php └── NoOpErrorHandlerTest.php ├── EventTests ├── DefaultEventDispatcherTest.php ├── EventBuilderTest.php └── LogEventTest.php ├── LoggerTests ├── DefaultLoggerTest.php └── NoOpLoggerTest.php ├── NotificationTests └── NotificationCenterTest.php ├── OptimizelyConfigTests ├── OptimizelyConfigServiceTest.php └── OptimizelyEntitiesTest.php ├── OptimizelyFactoryTest.php ├── OptimizelyTest.php ├── OptimizelyUserContextTest.php ├── ProjectConfigManagerTests ├── HTTPProjectConfigManagerTest.php └── StaticProjectConfigManagerTest.php ├── UserProfileTests ├── UserProfileTest.php └── UserProfileUtilsTest.php └── UtilsTests ├── ConditionTreeEvaluatorTest.php ├── CustomAttributeConditionEvaluatorLoggingTest.php ├── CustomAttributeConditionEvaluatorTest.php ├── EventTagUtilsTest.php ├── ValidatorLoggingTest.php ├── ValidatorTest.php └── VariableTypeUtilsTest.php /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: php-coveralls 2 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PHP SDK", 3 | 4 | "remoteEnv": { 5 | "SDK_ROOT": "/workspaces/php-sdk", 6 | "XDEBUG_CONFIG": "log_level=0", 7 | }, 8 | 9 | "image": "mcr.microsoft.com/devcontainers/php:0-8.2", 10 | 11 | "postStartCommand": "composer install", 12 | 13 | "forwardPorts": [ 14 | 8080 15 | ], 16 | "customizations": { 17 | "vscode": { 18 | "extensions": [ 19 | "bmewburn.vscode-intelephense-client", 20 | "xdebug.php-debug", 21 | "DEVSENSE.composer-php-vscode", 22 | "xdebug.php-pack", 23 | "recca0120.vscode-phpunit", 24 | "eamodio.gitlens" 25 | ] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG-REPORT.yml: -------------------------------------------------------------------------------- 1 | name: 🐞 Bug 2 | description: File a bug/issue 3 | title: "[BUG] " 4 | labels: ["bug", "needs-triage"] 5 | body: 6 | - type: checkboxes 7 | attributes: 8 | label: Is there an existing issue for this? 9 | description: Please search to see if an issue already exists for the bug you encountered. 10 | options: 11 | - label: I have searched the existing issues 12 | required: true 13 | - type: textarea 14 | attributes: 15 | label: SDK Version 16 | description: Version of the SDK in use? 17 | validations: 18 | required: true 19 | - type: textarea 20 | attributes: 21 | label: Current Behavior 22 | description: A concise description of what you're experiencing. 23 | validations: 24 | required: true 25 | - type: textarea 26 | attributes: 27 | label: Expected Behavior 28 | description: A concise description of what you expected to happen. 29 | validations: 30 | required: true 31 | - type: textarea 32 | attributes: 33 | label: Steps To Reproduce 34 | description: Steps to reproduce the behavior. 35 | placeholder: | 36 | 1. In this environment... 37 | 1. With this config... 38 | 1. Run '...' 39 | 1. See error... 40 | validations: 41 | required: true 42 | - type: textarea 43 | attributes: 44 | label: PHP Version 45 | description: What version of PHP are you using? 46 | validations: 47 | required: false 48 | - type: textarea 49 | attributes: 50 | label: Link 51 | description: Link to code demonstrating the problem. 52 | validations: 53 | required: false 54 | - type: textarea 55 | attributes: 56 | label: Logs 57 | description: Logs/stack traces related to the problem (⚠️do not include sensitive information). 58 | validations: 59 | required: false 60 | - type: dropdown 61 | attributes: 62 | label: Severity 63 | description: What is the severity of the problem? 64 | multiple: true 65 | options: 66 | - Blocking development 67 | - Affecting users 68 | - Minor issue 69 | validations: 70 | required: false 71 | - type: textarea 72 | attributes: 73 | label: Workaround/Solution 74 | description: Do you have any workaround or solution in mind for the problem? 75 | validations: 76 | required: false 77 | - type: textarea 78 | attributes: 79 | label: Recent Change 80 | description: Has this issue started happening after an update or experiment change? 81 | validations: 82 | required: false 83 | - type: textarea 84 | attributes: 85 | label: Conflicts 86 | description: Are there other libraries/dependencies potentially in conflict? 87 | validations: 88 | required: false 89 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ENHANCEMENT.yml: -------------------------------------------------------------------------------- 1 | name: ✨Enhancement 2 | description: Create a new ticket for a Enhancement/Tech-initiative for the benefit of the SDK which would be considered for a minor version update. 3 | title: "[ENHANCEMENT] <title>" 4 | labels: ["enhancement"] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Briefly describe the enhancement in a few sentences. 11 | placeholder: Short description... 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: benefits 16 | attributes: 17 | label: Benefits 18 | description: How would the enhancement benefit to your product or usage? 19 | placeholder: Benefits... 20 | validations: 21 | required: true 22 | - type: textarea 23 | id: detail 24 | attributes: 25 | label: Detail 26 | description: How would you like the enhancement to work? Please provide as much detail as possible 27 | placeholder: Detailed description... 28 | validations: 29 | required: false 30 | - type: textarea 31 | id: examples 32 | attributes: 33 | label: Examples 34 | description: Are there any examples of this enhancement in other products/services? If so, please provide links or references. 35 | placeholder: Links/References... 36 | validations: 37 | required: false 38 | - type: textarea 39 | id: risks 40 | attributes: 41 | label: Risks/Downsides 42 | description: Do you think this enhancement could have any potential downsides or risks? 43 | placeholder: Risks/Downsides... 44 | validations: 45 | required: false 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE-REQUEST.md: -------------------------------------------------------------------------------- 1 | <!-- 2 | Thanks for filing in issue! Are you requesting a new feature? If so, please share your feedback with us on the following link. 3 | --> 4 | ## Feedback requesting a new feature can be shared [here.](https://feedback.optimizely.com/) 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 💡Feature Requests 4 | url: https://feedback.optimizely.com/ 5 | about: Feedback requesting a new feature can be shared here. 6 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | - The "what"; a concise description of each logical change 3 | - Another change 4 | 5 | The "why", or other context. 6 | 7 | ## Test plan 8 | 9 | ## Issues 10 | - "THING-1234" or "Fixes #123" 11 | -------------------------------------------------------------------------------- /.github/workflows/integration_test.yml: -------------------------------------------------------------------------------- 1 | name: Reusable action of running integration of production suite 2 | 3 | on: 4 | workflow_call: 5 | secrets: 6 | CI_USER_TOKEN: 7 | required: true 8 | TRAVIS_COM_TOKEN: 9 | required: true 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | # You should create a personal access token and store it in your repository 17 | token: ${{ secrets.CI_USER_TOKEN }} 18 | repository: 'optimizely/travisci-tools' 19 | path: 'home/runner/travisci-tools' 20 | ref: 'master' 21 | - name: set SDK Branch if PR 22 | env: 23 | HEAD_REF: ${{ github.head_ref }} 24 | if: ${{ github.event_name == 'pull_request' }} 25 | run: | 26 | echo "SDK_BRANCH=$HEAD_REF" >> $GITHUB_ENV 27 | - name: set SDK Branch if not pull request 28 | env: 29 | REF_NAME: ${{github.ref_name}} 30 | if: ${{ github.event_name != 'pull_request' }} 31 | run: | 32 | echo "SDK_BRANCH=$REF_NAME" >> $GITHUB_ENV 33 | echo "TRAVIS_BRANCH=$REF_NAME}" >> $GITHUB_ENV 34 | - name: Trigger build 35 | env: 36 | SDK: php 37 | FULLSTACK_TEST_REPO: ${{ inputs.FULLSTACK_TEST_REPO }} 38 | BUILD_NUMBER: ${{ github.run_id }} 39 | TESTAPP_BRANCH: master 40 | GITHUB_TOKEN: ${{ secrets.CI_USER_TOKEN }} 41 | EVENT_TYPE: ${{ github.event_name }} 42 | GITHUB_CONTEXT: ${{ toJson(github) }} 43 | #REPO_SLUG: ${{ github.repository }} 44 | PULL_REQUEST_SLUG: ${{ github.repository }} 45 | UPSTREAM_REPO: ${{ github.repository }} 46 | PULL_REQUEST_SHA: ${{ github.event.pull_request.head.sha }} 47 | PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} 48 | UPSTREAM_SHA: ${{ github.sha }} 49 | TOKEN: ${{ secrets.TRAVIS_COM_TOKEN }} 50 | EVENT_MESSAGE: ${{ github.event.message }} 51 | HOME: 'home/runner' 52 | run: | 53 | echo "$GITHUB_CONTEXT" 54 | home/runner/travisci-tools/trigger-script-with-status-update.sh 55 | -------------------------------------------------------------------------------- /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: PHP 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | linting: 11 | name: Linting 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v3 16 | - name: Set up PHP 17 | uses: shivammathur/setup-php@v2 18 | with: 19 | php-version: '8.2' 20 | - name: Install php code sniffer 21 | run: composer require "squizlabs/php_codesniffer=*" 22 | - name: Run linting 23 | run: composer lint 24 | 25 | source_clear: 26 | name: Source Clear Scan 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout code 30 | uses: actions/checkout@v3 31 | - name: Source clear scan 32 | env: 33 | SRCCLR_API_TOKEN: ${{ secrets.SRCCLR_API_TOKEN }} 34 | run: curl -sSL https://download.sourceclear.com/ci.sh | bash -s – scan 35 | 36 | unit_tests: 37 | name: Unit Tests ${{ matrix.php-versions }} 38 | needs: [ linting, source_clear ] 39 | runs-on: ubuntu-latest 40 | strategy: 41 | fail-fast: false 42 | matrix: 43 | php-versions: [ '8.1', '8.2' ] 44 | steps: 45 | - name: Checkout code 46 | uses: actions/checkout@v3 47 | - name: Set up PHP v${{ matrix.php-versions }} 48 | uses: shivammathur/setup-php@v2 49 | with: 50 | php-version: ${{ matrix.php-versions }} 51 | - name: Cache Composer packages 52 | id: composer-cache 53 | uses: actions/cache@v3 54 | with: 55 | path: vendor 56 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 57 | restore-keys: | 58 | ${{ runner.os }}-php- 59 | - name: Install dependencies 60 | run: composer install 61 | - name: Run tests 62 | run: | 63 | mkdir -p ./build/logs 64 | ./vendor/bin/phpunit --coverage-clover ./build/logs/clover.xml 65 | - name: Verify clover.xml created 66 | run: | 67 | if [ ! -f ./build/logs/clover.xml ]; then 68 | echo "clover.xml was not created" 69 | exit 1 70 | fi 71 | - name: Upload coverage results to Coveralls 72 | env: 73 | COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} 74 | run: | 75 | composer global require php-coveralls/php-coveralls 76 | php-coveralls --coverage_clover=./build/logs/clover.xml -v 77 | 78 | integration_tests: 79 | name: Integration Tests 80 | needs: [ unit_tests ] 81 | uses: optimizely/php-sdk/.github/workflows/integration_test.yml@master 82 | secrets: 83 | CI_USER_TOKEN: ${{ secrets.CI_USER_TOKEN }} 84 | TRAVIS_COM_TOKEN: ${{ secrets.TRAVIS_COM_TOKEN }} 85 | -------------------------------------------------------------------------------- /.github/workflows/ticket_reference_check.yml: -------------------------------------------------------------------------------- 1 | name: Jira ticket reference check 2 | 3 | on: 4 | pull_request: 5 | types: [opened, edited, reopened, synchronize] 6 | 7 | jobs: 8 | 9 | jira_ticket_reference_check: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Check for Jira ticket reference 14 | uses: optimizely/github-action-ticket-reference-checker-public@master 15 | with: 16 | bodyRegex: 'FSSDK-(?<ticketNumber>\d+)' 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | build/ 3 | vendor/ 4 | composer.phar 5 | .phpunit.result.cache 6 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This is a comment. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # These owners will be the default owners for everything in the repo. 5 | # Unless a later match takes precedence, @global-owner1 and @global-owner2 6 | # will be requested for review when someone opens a pull request. 7 | * @optimizely/fullstack-devs 8 | 9 | # Order is important; the last matching pattern takes the most precedence. 10 | # When someone opens a pull request that only modifies JS files, only @js-owner 11 | # and not the global owner(s) will be requested for a review. 12 | #*.js @js-owner 13 | 14 | # You can also use email addresses if you prefer. They'll be used to look up 15 | # users just like we do for commit author emails. 16 | #docs/* docs@example.com 17 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the Optimizely PHP SDK 2 | 3 | We welcome contributions and feedback! All contributors must sign our [Contributor License Agreement (CLA)](https://docs.google.com/a/optimizely.com/forms/d/e/1FAIpQLSf9cbouWptIpMgukAKZZOIAhafvjFCV8hS00XJLWQnWDFtwtA/viewform) to be eligible to contribute. Please read the [README](README.md) to set up your development environment, then read the guidelines below for information on submitting your code. 4 | 5 | ## Development process 6 | 7 | 1. Fork the repository and create your branch from master. 8 | 2. Please follow the [commit message guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines) for each commit message. 9 | 3. Make sure to add tests! 10 | 4. `git push` your changes to GitHub. 11 | 5. Open a PR from your fork into the master branch of the original repo. 12 | 6. Make sure that all unit tests are passing and that there are no merge conflicts between your branch and `master`. 13 | 7. Open a pull request from `YOUR_NAME/branch_name` to `master`. 14 | 8. A repository maintainer will review your pull request and, if all goes well, squash and merge it! 15 | 16 | ## Pull request acceptance criteria 17 | 18 | * **All code must have test coverage.** We use PHPUnit. Changes in functionality should have accompanying unit tests. Bug fixes should have accompanying regression tests. 19 | * Tests are located in `tests` with one file per class. 20 | * Lint your code with PHP CodeSniffer before submitting. 21 | 22 | ## Style 23 | We enforce [PSR-2](https://www.php-fig.org/psr/psr-2/) rules with some minor [deviations](phpcs.xml). Run linter by executing `composer lint` and autocorrect lint errors by executing `composer beautify`. 24 | 25 | 26 | ## License 27 | 28 | All contributions are under the CLA mentioned above. For this project, Optimizely uses the Apache 2.0 license, and so asks that by contributing your code, you agree to license your contribution under the terms of the [Apache License v2.0](http://www.apache.org/licenses/LICENSE-2.0). Your contributions should also include the following header: 29 | 30 | ``` 31 | /**************************************************************************** 32 | * Copyright YEAR, Optimizely, Inc. and contributors * 33 | * * 34 | * Licensed under the Apache License, Version 2.0 (the "License"); * 35 | * you may not use this file except in compliance with the License. * 36 | * You may obtain a copy of the License at * 37 | * * 38 | * http://www.apache.org/licenses/LICENSE-2.0 * 39 | * * 40 | * Unless required by applicable law or agreed to in writing, software * 41 | * distributed under the License is distributed on an "AS IS" BASIS, * 42 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 43 | * See the License for the specific language governing permissions and * 44 | * limitations under the License. * 45 | ***************************************************************************/ 46 | ``` 47 | 48 | The YEAR above should be the year of the contribution. If work on the file has been done over multiple years, list each year in the section above. Example: Optimizely writes the file and releases it in 2014. No changes are made in 2015. Change made in 2016. YEAR should be “2014, 2016”. 49 | 50 | ## Contact 51 | 52 | If you have questions, please contact developers@optimizely.com. 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Optimizely PHP SDK 2 | [![Packagist](https://badgen.net/packagist/v/optimizely/optimizely-sdk)](https://packagist.org/packages/optimizely/optimizely-sdk) 3 | [![Build Status](https://github.com/optimizely/php-sdk/actions/workflows/php.yml/badge.svg?branch=master)](https://github.com/optimizely/php-sdk/actions/workflows/php.yml?query=branch%3Amaster) 4 | [![Coverage Status](https://coveralls.io/repos/github/optimizely/php-sdk/badge.svg?branch=master)](https://coveralls.io/github/optimizely/php-sdk?branch=master) 5 | [![Total Downloads](https://poser.pugx.org/optimizely/optimizely-sdk/downloads)](https://packagist.org/packages/optimizely/optimizely-sdk) 6 | [![Apache 2.0](https://img.shields.io/github/license/nebula-plugins/gradle-extra-configurations-plugin.svg)](http://www.apache.org/licenses/LICENSE-2.0) 7 | 8 | This repository houses the PHP SDK for use with Optimizely Feature Experimentation and Optimizely Full Stack (legacy). 9 | 10 | Optimizely Feature Experimentation is an A/B testing and feature management tool for product development teams that enables you to experiment at every step. Using Optimizely Feature Experimentation allows for every feature on your roadmap to be an opportunity to discover hidden insights. Learn more at [Optimizely.com](https://www.optimizely.com/products/experiment/feature-experimentation/), or see the [developer documentation](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/welcome). 11 | 12 | Optimizely Rollouts is [free feature flags](https://www.optimizely.com/free-feature-flagging/) for development teams. You can easily roll out and roll back features in any application without code deploys, mitigating risk for every feature on your roadmap. 13 | 14 | ## Get Started 15 | 16 | Refer to the [PHP SDK's developer documentation](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/php-sdk) for detailed instructions on getting started with using the SDK. 17 | 18 | ### Requirements 19 | 20 | To access the Feature Management configuration in the Optimizely dashboard, please contact your Optimizely account executive. 21 | 22 | SDK version 4.0.0 requires PHP8+. 23 | SDK version 3 requires PHP5.5+ up to PHP7. 24 | 25 | ### Install the SDK 26 | 27 | The Optimizely PHP SDK can be installed through [Composer](https://getcomposer.org/). Please use the following command: 28 | 29 | ```bash 30 | php composer.phar require optimizely/optimizely-sdk 31 | ``` 32 | 33 | ## Use the PHP SDK 34 | 35 | ### Initialization 36 | 37 | Create the Optimizely client, for example: 38 | 39 | ```php 40 | <?php 41 | 42 | use Optimizely\Optimizely; 43 | 44 | $optimizely = new Optimizely(<<DATAFILE>>); 45 | ``` 46 | 47 | Or you may also use OptimizelyFactory method to create an optimizely client using your SDK key, an optional fallback datafile and an optional datafile access token. Using this method internally creates an HTTPProjectConfigManager. See [HTTPProjectConfigManager](#use-httpprojectconfigmanager) for further detail. 48 | 49 | ```php 50 | <?php 51 | 52 | use Optimizely\OptimizelyFactory; 53 | 54 | $optimizelyClient = OptimizelyFactory::createDefaultInstance( 55 | "your-sdk-key", 56 | <<DATAFILE>>, 57 | <<DATAFILE_AUTH_TOKEN>> 58 | ); 59 | ``` 60 | To access your HTTPProjectConfigManager: 61 | 62 | ```php 63 | <?php 64 | 65 | use Optimizely\Optimizely; 66 | 67 | /** @var Optimizely $optimizelyClient */ 68 | $configManager = $optimizelyClient->configManager; 69 | ``` 70 | 71 | Or you can also provide an implementation of the [`ProjectConfigManagerInterface`](https://github.com/optimizely/php-sdk/blob/master/src/Optimizely/ProjectConfigManager/ProjectConfigManagerInterface.php) in the constructor: 72 | 73 | ```php 74 | <?php 75 | 76 | use Optimizely\Optimizely; 77 | use Optimizely\ProjectConfigManager\HTTPProjectConfigManager; 78 | 79 | $configManager = new HTTPProjectConfigManager(<<SDK_KEY>>); 80 | $optimizely = new Optimizely( 81 | <<DATAFILE>>, 82 | null, 83 | null, 84 | null, 85 | false, 86 | null, 87 | $configManager 88 | ); 89 | ``` 90 | 91 | ### ProjectConfigManagerInterface 92 | [`ProjectConfigManagerInterface`](https://github.com/optimizely/php-sdk/blob/master/src/Optimizely/ProjectConfigManager/ProjectConfigManagerInterface.php) exposes `getConfig` method for retrieving `ProjectConfig` instance. 93 | 94 | ### <a name="http_config_manager"></a> HTTPProjectConfigManager 95 | 96 | [`HTTPProjectConfigManager`](https://github.com/optimizely/php-sdk/blob/master/src/Optimizely/ProjectConfigManager/HTTPProjectConfigManager.php) 97 | is an implementation of `ProjectConfigManagerInterface` interface. 98 | 99 | The `fetch` method makes a blocking HTTP GET request to the configured URL to download the 100 | project datafile and initialize an instance of the ProjectConfig. 101 | 102 | Calling `fetch` will update the internal ProjectConfig instance that will be returned by `getConfig`. 103 | 104 | ### Use HTTPProjectConfigManager 105 | 106 | ```php 107 | <?php 108 | 109 | use Optimizely\ProjectConfigManager\HTTPProjectConfigManager; 110 | 111 | $configManager = new HTTPProjectConfigManager(<<SDK_KEY>>); 112 | ``` 113 | 114 | ### SDK key 115 | Optimizely project SDK key; required unless source URL is overridden. 116 | 117 | A notification will be triggered whenever a _new_ datafile is fetched and ProjectConfig is updated. To subscribe to these notifications, use the `$notificationCenter->addNotificationListener(NotificationType::OPTIMIZELY_CONFIG_UPDATE, $updateCallback)`. 118 | 119 | ## SDK Development 120 | 121 | ### Unit Tests 122 | 123 | You can run all unit tests with: 124 | 125 | ```bash 126 | ./vendor/bin/phpunit 127 | ``` 128 | 129 | ### Contributing 130 | 131 | Please see [CONTRIBUTING](CONTRIBUTING.md). 132 | 133 | ### Other Optimizely SDKs 134 | 135 | - Agent - https://github.com/optimizely/agent 136 | 137 | - Android - https://github.com/optimizely/android-sdk 138 | 139 | - C# - https://github.com/optimizely/csharp-sdk 140 | 141 | - Flutter - https://github.com/optimizely/optimizely-flutter-sdk 142 | 143 | - Go - https://github.com/optimizely/go-sdk 144 | 145 | - Java - https://github.com/optimizely/java-sdk 146 | 147 | - JavaScript - https://github.com/optimizely/javascript-sdk 148 | 149 | - PHP - https://github.com/optimizely/php-sdk 150 | 151 | - Python - https://github.com/optimizely/python-sdk 152 | 153 | - React - https://github.com/optimizely/react-sdk 154 | 155 | - Ruby - https://github.com/optimizely/ruby-sdk 156 | 157 | - Swift - https://github.com/optimizely/swift-sdk 158 | -------------------------------------------------------------------------------- /bug-bash/Decide.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace Optimizely\BugBash; 4 | 5 | require_once '../vendor/autoload.php'; 6 | require_once '../bug-bash/_bug-bash-autoload.php'; 7 | 8 | use Monolog\Logger; 9 | use Optimizely\Decide\OptimizelyDecideOption; 10 | use Optimizely\Logger\DefaultLogger; 11 | use Optimizely\Notification\NotificationType; 12 | use Optimizely\Optimizely; 13 | use Optimizely\OptimizelyFactory; 14 | use Optimizely\OptimizelyUserContext; 15 | 16 | // 1. Change this SDK key to your project's SDK Key 17 | const SDK_KEY = '<your-sdk-key>'; 18 | 19 | // 2. Change this to your flag key 20 | const FLAG_KEY = '<your-flag-key>'; 21 | 22 | // 3. Uncomment each scenario 1 by 1 modifying the contents of the method 23 | // to test additional scenarios. 24 | 25 | $test = new DecideTests(); 26 | $test->verifyDecisionProperties(); 27 | // $test->testWithVariationsOfDecideOptions(); 28 | // $test->verifyLogsImpressionsEventsDispatched(); 29 | // $test->verifyResultsPageInYourProjectShowsImpressionEvent(); 30 | // $test->verifyDecisionListenerWasCalled(); 31 | // $test->verifyAnInvalidFlagKeyIsHandledCorrectly(); 32 | 33 | // 4. Change the current folder into the bug-bash directory 34 | // cd bug-bash/ 35 | 36 | // 5. Run the following command to execute the uncommented tests above: 37 | // php Decide.php 38 | 39 | // https://docs.developers.optimizely.com/feature-experimentation/docs/decide-methods-php 40 | class DecideTests 41 | { 42 | // verify decision return properties with default DecideOptions 43 | public function verifyDecisionProperties(): void 44 | { 45 | $decision = $this->userContext->decide(FLAG_KEY); 46 | 47 | $this->printDecision($decision, "Check that the following decision properties are expected for user $this->userId"); 48 | } 49 | 50 | // test decide w all options: DISABLE_DECISION_EVENT, ENABLED_FLAGS_ONLY, IGNORE_USER_PROFILE_SERVICE, INCLUDE_REASONS, EXCLUDE_VARIABLES (will need to add variables) 51 | public function testWithVariationsOfDecideOptions(): void 52 | { 53 | $options = [ 54 | OptimizelyDecideOption::INCLUDE_REASONS, 55 | // OptimizelyDecideOption::DISABLE_DECISION_EVENT, 56 | // OptimizelyDecideOption::ENABLED_FLAGS_ONLY, // ⬅️ Disable some of your flags 57 | // OptimizelyDecideOption::IGNORE_USER_PROFILE_SERVICE, 58 | // OptimizelyDecideOption::EXCLUDE_VARIABLES, 59 | ]; 60 | 61 | $decision = $this->userContext->decide(FLAG_KEY, $options); 62 | 63 | $this->printDecision($decision, 'Modify the OptimizelyDecideOptions and check the decision variables expected'); 64 | } 65 | 66 | // verify in logs that impression event of this decision was dispatched 67 | public function verifyLogsImpressionsEventsDispatched(): void 68 | { 69 | // 💡️ Create a new flag with an A/B Test eg "product_version" 70 | $featureFlagKey = 'product_version'; 71 | $logger = new DefaultLogger(Logger::DEBUG); 72 | $localOptimizelyClient = new Optimizely(datafile: null, logger: $logger, sdkKey: SDK_KEY); 73 | $localUserContext = $localOptimizelyClient->createUserContext($this->userId); 74 | 75 | // review the DEBUG output, ensuring you see an impression log 76 | // "Dispatching impression event to URL https://logx.optimizely.com/v1/events with params..." 77 | $localUserContext->decide($featureFlagKey); 78 | } 79 | 80 | // verify on Results page that impression even was created 81 | public function verifyResultsPageInYourProjectShowsImpressionEvent(): void 82 | { 83 | print "Go to your project's results page and verify decisions events are showing (5 min delay)"; 84 | } 85 | 86 | // verify that decision listener contains correct information 87 | public function verifyDecisionListenerWasCalled(): void 88 | { 89 | // Check that this was called during the... 90 | $onDecision = function ($type, $userId, $attributes, $decisionInfo) { 91 | print ">>> [$this->outputTag] OnDecision: 92 | type: $type, 93 | userId: $userId, 94 | attributes: " . print_r($attributes, true) . " 95 | decisionInfo: " . print_r($decisionInfo, true) . "\r\n"; 96 | }; 97 | $this->optimizelyClient->notificationCenter->addNotificationListener( 98 | NotificationType::DECISION, 99 | $onDecision 100 | ); 101 | 102 | // ...decide. 103 | $this->userContext->decide(FLAG_KEY); 104 | } 105 | 106 | // verify that invalid flag key is handled correctly 107 | public function verifyAnInvalidFlagKeyIsHandledCorrectly(): void 108 | { 109 | $logger = new DefaultLogger(Logger::ERROR); 110 | $localOptimizelyClient = new Optimizely(datafile: null, logger: $logger, sdkKey: SDK_KEY); 111 | $userId = 'user-' . mt_rand(10, 99); 112 | $localUserContext = $localOptimizelyClient->createUserContext($userId); 113 | 114 | // ensure you see an error -- Optimizely.ERROR: FeatureFlag Key "a_key_not_in_the_project" is not in datafile. 115 | $localUserContext->decide("a_key_not_in_the_project"); 116 | } 117 | 118 | private Optimizely $optimizelyClient; 119 | private string $userId; 120 | private ?OptimizelyUserContext $userContext; 121 | private string $outputTag = "Decide"; 122 | 123 | public function __construct() 124 | { 125 | $this->optimizelyClient = OptimizelyFactory::createDefaultInstance(SDK_KEY); 126 | 127 | $this->userId = 'user-' . mt_rand(10, 99); 128 | $attributes = ['age' => 25, 'country' => 'canada', 'abandoned_cart' => false]; 129 | $this->userContext = $this->optimizelyClient->createUserContext($this->userId, $attributes); 130 | } 131 | 132 | private function printDecision($decision, $message): void 133 | { 134 | $enabled = $decision->getEnabled() ? "true" : "false"; 135 | 136 | print ">>> [$this->outputTag] $message: 137 | enabled: $enabled, 138 | flagKey: {$decision->getFlagKey()}, 139 | ruleKey: {$decision->getRuleKey()}, 140 | variationKey: {$decision->getVariationKey()}, 141 | variables: " . print_r($decision->getVariables(), true) . ", 142 | reasons: " . print_r($decision->getReasons(), true) . "\r\n"; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /bug-bash/DecideAll.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace Optimizely\BugBash; 4 | 5 | require_once '../vendor/autoload.php'; 6 | require_once '../bug-bash/_bug-bash-autoload.php'; 7 | 8 | use Monolog\Logger; 9 | use Optimizely\Decide\OptimizelyDecideOption; 10 | use Optimizely\Logger\DefaultLogger; 11 | use Optimizely\Notification\NotificationType; 12 | use Optimizely\Optimizely; 13 | use Optimizely\OptimizelyFactory; 14 | use Optimizely\OptimizelyUserContext; 15 | 16 | // 1. Change this SDK key to your project's SDK Key 17 | const SDK_KEY = '<your-sdk-key>'; 18 | 19 | // 2. Create additional flag keys in your project (2+) 20 | 21 | // 3. Uncomment each scenario 1 by 1 modifying the contents of the method 22 | // to test additional scenarios. 23 | 24 | $test = new DecideAllTests(); 25 | $test->verifyDecisionProperties(); 26 | // $test->testWithVariousCombinationsOfOptions(); 27 | // $test->verifyLogImpressionEventDispatched(); 28 | // $test->verifyResultsPageShowsImpressionEvents(); 29 | // $test->verifyDecisionListenerContainsCorrectInformation(); 30 | 31 | // 4. Change the current folder into the bug-bash directory if you're not already there: 32 | // cd bug-bash/ 33 | 34 | // 5. Run the following command to execute the uncommented tests above: 35 | // php DecideAll.php 36 | 37 | // https://docs.developers.optimizely.com/feature-experimentation/docs/decide-methods-php 38 | class DecideAllTests 39 | { 40 | // verify decide all returns properties without specifying default options 41 | public function verifyDecisionProperties(): void 42 | { 43 | $decision = $this->userContext->decideAll(); 44 | 45 | $this->printDecisions($decision, "Check that all of the decisions' multiple properties are expected for user `$this->userId`"); 46 | } 47 | 48 | // test with all and variations/combinations of options 49 | public function testWithVariousCombinationsOfOptions(): void 50 | { 51 | $options = [ 52 | OptimizelyDecideOption::INCLUDE_REASONS, 53 | // OptimizelyDecideOption::DISABLE_DECISION_EVENT, 54 | // OptimizelyDecideOption::ENABLED_FLAGS_ONLY, // ⬅️ Disable some of your flags 55 | // OptimizelyDecideOption::IGNORE_USER_PROFILE_SERVICE, 56 | OptimizelyDecideOption::EXCLUDE_VARIABLES, 57 | ]; 58 | 59 | $decisions = $this->userContext->decideAll($options); 60 | 61 | $this->printDecisions($decisions, "Check that all of your flags' decisions respected the options passed."); 62 | } 63 | 64 | // verify in logs that impression event of this decision was dispatched 65 | public function verifyLogImpressionEventDispatched(): void 66 | { 67 | // 💡️ Be sure you have >=1 of your project's flags has an EXPERIMENT type 68 | $logger = new DefaultLogger(Logger::DEBUG); 69 | $localOptimizelyClient = new Optimizely(datafile: null, logger: $logger, sdkKey: SDK_KEY); 70 | $localUserContext = $localOptimizelyClient->createUserContext($this->userId); 71 | 72 | // review the DEBUG output, ensuring you see an impression log for each *EXPERIMENT* with a message like 73 | // "Dispatching impression event to URL https://logx.optimizely.com/v1/events with params..." 74 | // ⚠️ Rollout flag types should not dispatch and impression event 75 | $localUserContext->decideAll(); 76 | } 77 | 78 | // verify on Results page that impression events was created 79 | public function verifyResultsPageShowsImpressionEvents(): void 80 | { 81 | print "After about 5-10 minutes, go to your project's results page and verify decisions events are showing."; 82 | } 83 | 84 | // verify that decision listener contains correct information 85 | public function verifyDecisionListenerContainsCorrectInformation(): void 86 | { 87 | // Check that this was called for each of your project flag keys 88 | $onDecision = function ($type, $userId, $attributes, $decisionInfo) { 89 | print ">>> [$this->outputTag] OnDecision: 90 | type: $type, 91 | userId: $userId, 92 | attributes: " . print_r($attributes, true) . " 93 | decisionInfo: " . print_r($decisionInfo, true) . "\r\n"; 94 | }; 95 | $this->optimizelyClient->notificationCenter->addNotificationListener( 96 | NotificationType::DECISION, 97 | $onDecision 98 | ); 99 | 100 | $this->userContext->decideAll(); 101 | } 102 | 103 | private Optimizely $optimizelyClient; 104 | private string $userId; 105 | private ?OptimizelyUserContext $userContext; 106 | private string $outputTag = "Decide All"; 107 | 108 | public function __construct() 109 | { 110 | $this->optimizelyClient = OptimizelyFactory::createDefaultInstance(SDK_KEY); 111 | 112 | $this->userId = 'user-' . mt_rand(10, 99); 113 | $attributes = ['country' => 'nederland', 'age' => 43, 'is_return_visitor' => true]; 114 | $this->userContext = $this->optimizelyClient->createUserContext($this->userId, $attributes); 115 | } 116 | 117 | private function printDecisions($decisions, $message): void 118 | { 119 | $count = 0; 120 | foreach ($decisions as $decision) { 121 | $enabled = $decision->getEnabled() ? "true" : "false"; 122 | 123 | print ">>> [$this->outputTag #$count] $message: 124 | enabled: $enabled, 125 | flagKey: {$decision->getFlagKey()}, 126 | ruleKey: {$decision->getRuleKey()}, 127 | variationKey: {$decision->getVariationKey()}, 128 | variables: " . print_r($decision->getVariables(), true) . ", 129 | reasons: " . print_r($decision->getReasons(), true) . "\r\n"; 130 | 131 | $count++; 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /bug-bash/DecideForKeys.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace Optimizely\BugBash; 4 | 5 | require_once '../vendor/autoload.php'; 6 | require_once '../bug-bash/_bug-bash-autoload.php'; 7 | 8 | use Monolog\Logger; 9 | use Optimizely\Decide\OptimizelyDecideOption; 10 | use Optimizely\Logger\DefaultLogger; 11 | use Optimizely\Notification\NotificationType; 12 | use Optimizely\Optimizely; 13 | use Optimizely\OptimizelyFactory; 14 | use Optimizely\OptimizelyUserContext; 15 | 16 | // 1. Change this SDK key to your project's SDK Key 17 | const SDK_KEY = '<your-sdk-key>'; 18 | 19 | // 2. Check that you have 3+ flag keys in your project and add them here 20 | const FLAG_KEYS = ['<your-flag-key-1>', '<your-flag-key-2>', '<your-flag-key-3>']; 21 | 22 | // 3. Uncomment each scenario 1 by 1 modifying the contents of the method 23 | // to test additional scenarios. 24 | 25 | $test = new DecideForKeysTests(); 26 | $test->verifyDecisionProperties(); 27 | // $test->testWithVariationsOfDecideOptions(); 28 | // $test->verifyLogsImpressionsEventsDispatched(); 29 | // $test->verifyResultsPageInYourProjectShowsImpressionEvent(); 30 | // $test->verifyDecisionListenerWasCalled(); 31 | // $test->verifyAnInvalidFlagKeyIsHandledCorrectly(); 32 | 33 | // 4. Change the current folder into the bug-bash directory if you've not already 34 | // cd bug-bash/ 35 | 36 | // 5. Run the following command to execute the uncommented tests above: 37 | // php DecideForKeys.php 38 | 39 | // https://docs.developers.optimizely.com/feature-experimentation/docs/decide-methods-php 40 | class DecideForKeysTests 41 | { 42 | 43 | // verify decision return properties with default DecideOptions 44 | public function verifyDecisionProperties(): void 45 | { 46 | $decision = $this->userContext->decideForKeys(FLAG_KEYS); 47 | 48 | $this->printDecisions($decision, "Check that the following decisions' properties are expected"); 49 | } 50 | 51 | // test decide w all options: DISABLE_DECISION_EVENT, ENABLED_FLAGS_ONLY, IGNORE_USER_PROFILE_SERVICE, INCLUDE_REASONS, EXCLUDE_VARIABLES (will need to add variables) 52 | public function testWithVariationsOfDecideOptions(): void 53 | { 54 | $options = [ 55 | OptimizelyDecideOption::INCLUDE_REASONS, 56 | // OptimizelyDecideOption::DISABLE_DECISION_EVENT, 57 | // OptimizelyDecideOption::ENABLED_FLAGS_ONLY, // ⬅️ Disable some of your flags 58 | // OptimizelyDecideOption::IGNORE_USER_PROFILE_SERVICE, 59 | // OptimizelyDecideOption::EXCLUDE_VARIABLES, 60 | ]; 61 | 62 | $decision = $this->userContext->decideForKeys(FLAG_KEYS, $options); 63 | 64 | $this->printDecisions($decision, "Modify the OptimizelyDecideOptions and check all the decisions' are as expected"); 65 | } 66 | 67 | // verify in logs that impression event of this decision was dispatched 68 | public function verifyLogsImpressionsEventsDispatched(): void 69 | { 70 | // 💡️ Be sure that your FLAG_KEYS array above includes A/B Test eg "product_version" 71 | $logger = new DefaultLogger(Logger::DEBUG); 72 | $localOptimizelyClient = new Optimizely(datafile: null, logger: $logger, sdkKey: SDK_KEY); 73 | $localUserContext = $localOptimizelyClient->createUserContext($this->userId); 74 | 75 | // review the DEBUG output, ensuring you see an impression log for each experiment type in your FLAG_KEYS 76 | // "Dispatching impression event to URL https://logx.optimizely.com/v1/events with params..." 77 | // ⚠️ Your Rollout type flags should not have impression events 78 | $localUserContext->decideForKeys(FLAG_KEYS); 79 | } 80 | 81 | // verify on Results page that impression even was created 82 | public function verifyResultsPageInYourProjectShowsImpressionEvent(): void 83 | { 84 | print "Go to your project's results page and verify decisions events are showing (5 min delay)"; 85 | } 86 | 87 | // verify that decision listener contains correct information 88 | public function verifyDecisionListenerWasCalled(): void 89 | { 90 | // Check that this was called during the... 91 | $onDecision = function ($type, $userId, $attributes, $decisionInfo) { 92 | print ">>> [$this->outputTag] OnDecision: 93 | type: $type, 94 | userId: $userId, 95 | attributes: " . print_r($attributes, true) . " 96 | decisionInfo: " . print_r($decisionInfo, true) . "\r\n"; 97 | }; 98 | $this->optimizelyClient->notificationCenter->addNotificationListener( 99 | NotificationType::DECISION, 100 | $onDecision 101 | ); 102 | 103 | // ...decide. 104 | $this->userContext->decide(FLAG_KEY); 105 | } 106 | 107 | // verify that invalid flag key is handled correctly 108 | public function verifyAnInvalidFlagKeyIsHandledCorrectly(): void 109 | { 110 | $logger = new DefaultLogger(Logger::ERROR); 111 | $localOptimizelyClient = new Optimizely(datafile: null, logger: $logger, sdkKey: SDK_KEY); 112 | $userId = 'user-' . mt_rand(10, 99); 113 | $localUserContext = $localOptimizelyClient->createUserContext($userId); 114 | 115 | // ensure you see an error -- Optimizely.ERROR: FeatureFlag Key "a_key_not_in_the_project" is not in datafile. 116 | $localUserContext->decide("a_key_not_in_the_project"); 117 | } 118 | 119 | private Optimizely $optimizelyClient; 120 | private string $userId; 121 | private ?OptimizelyUserContext $userContext; 122 | private string $outputTag = "Decide For Keys"; 123 | 124 | public function __construct() 125 | { 126 | $this->optimizelyClient = OptimizelyFactory::createDefaultInstance(SDK_KEY); 127 | 128 | $this->userId = 'user-' . mt_rand(10, 99); 129 | $attributes = ['likes_yams' => true, 'cart_value' => 34.13, 'country' => 'sweden']; 130 | $this->userContext = $this->optimizelyClient->createUserContext($this->userId, $attributes); 131 | } 132 | 133 | private function printDecisions($decisions, $message): void 134 | { 135 | $count = 0; 136 | foreach ($decisions as $decision) { 137 | $enabled = $decision->getEnabled() ? "true" : "false"; 138 | 139 | print ">>> [$this->outputTag #$count] $message: 140 | enabled: $enabled, 141 | flagKey: {$decision->getFlagKey()}, 142 | ruleKey: {$decision->getRuleKey()}, 143 | variationKey: {$decision->getVariationKey()}, 144 | variables: " . print_r($decision->getVariables(), true) . ", 145 | reasons: " . print_r($decision->getReasons(), true) . "\r\n"; 146 | 147 | $count++; 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /bug-bash/OptiConfig.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace Optimizely\BugBash; 4 | 5 | require_once '../vendor/autoload.php'; 6 | require_once '../bug-bash/_bug-bash-autoload.php'; 7 | 8 | use Optimizely\Optimizely; 9 | use Optimizely\Decide\OptimizelyDecideOption; 10 | 11 | // To test optimizely config simply add your SDK key and attributes in, then run the file. 12 | // You should be able to see unpacked entities from featureMap and experimentMap 13 | // verify them and make sure some are not missing or error 14 | 15 | // Instantiate an Optimizely client 16 | $sdkKey = "<your sdk key here>"; 17 | // $optimizelyClient = new Optimizely($sdkKey); 18 | $optimizelyClient = new Optimizely(null, null, null, null, false, null, null, null, $sdkKey); 19 | $user = $optimizelyClient->createUserContext('user123', ['attribute1' => 'hello']); 20 | $decision = $user->decide('flag1', [OptimizelyDecideOption::INCLUDE_REASONS]); 21 | 22 | $reasons = $decision->getReasons(); 23 | echo "[OptimizelyConfig] reasons: " . json_encode($reasons) . PHP_EOL; 24 | echo "[OptimizelyConfig - flag key]: " . $decision->getFlagKey() . PHP_EOL; 25 | echo "[OptimizelyConfig - rule key]: " . $decision->getFlagKey() . PHP_EOL; 26 | echo "[OptimizelyConfig - enabled]: " . $decision->getEnabled() . PHP_EOL; 27 | echo "[OptimizelyConfig - variation key]: " . $decision->getVariationKey() . PHP_EOL; 28 | $variables = $decision->getVariables(); 29 | echo "[OptimizelyConfig - variables]: " . json_encode($variables) . PHP_EOL; 30 | echo PHP_EOL; 31 | 32 | $user->trackEvent('myevent'); 33 | 34 | echo "===========================" . PHP_EOL; 35 | echo " OPTIMIZELY CONFIG V2 " . PHP_EOL; 36 | echo "===========================" . PHP_EOL . PHP_EOL; 37 | 38 | $config = $optimizelyClient->getOptimizelyConfig(); 39 | // get the revision 40 | echo "[OptimizelyConfig] revision:" . $config->getRevision() . PHP_EOL; 41 | 42 | // get the SDK key 43 | echo "[OptimizelyConfig] SDKKey:" . $config->getSdkKey() . PHP_EOL; 44 | 45 | // get the environment key 46 | echo "[OptimizelyConfig] environmentKey:" . $config->getEnvironmentKey() . PHP_EOL; 47 | 48 | // all attributes 49 | echo "[OptimizelyConfig] attributes:" . PHP_EOL; 50 | $attributes = $config->getAttributes(); 51 | foreach($attributes as $attribute) 52 | { 53 | echo "[OptimizelyAttribute] -- (id, key) = ((" . $attribute->getId(). "), (". $attribute->getKey() . "))" . PHP_EOL; 54 | } 55 | 56 | // all audiences 57 | echo "[OptimizelyConfig] audiences:" . PHP_EOL; 58 | $audiences = $config->getAudiences(); 59 | foreach($audiences as $audience) 60 | { 61 | echo "[OptimizelyAudience] -- (id, key, conditions) = ((" . $audience->getId(). "), (". $audience->getName() . "), (". $audience->getConditions() . "))" . PHP_EOL; 62 | } 63 | 64 | // all events 65 | echo "[OptimizelyConfig] events:" . PHP_EOL; 66 | $events = $config->getEvents(); 67 | foreach($events as $event) 68 | { 69 | echo "[OptimizelyEvent] -- (id, key, experimentIds) = ((" . $event->getId(). "), (". $event->getKey() . "), (". $event->getExperimentIds() . "))" . PHP_EOL; 70 | } 71 | 72 | // all flags 73 | $flags = array_values((array)$config->getFeaturesMap()); 74 | foreach ($flags as $flag) 75 | { 76 | // Use experimentRules and deliverRules 77 | $experimentRules = $flag->getExperimentRules(); 78 | echo "------ Experiment rules -----" . PHP_EOL; 79 | foreach ($experimentRules as $experimentRule) 80 | { 81 | echo "---" . PHP_EOL; 82 | echo "[OptimizelyExperiment] - experiment rule-key = " . $experimentRule->getKey() . PHP_EOL; 83 | echo "[OptimizelyExperiment] - experiment audiences = " . PHP_EOL;$experimentRule->getExperimentAudiences(); 84 | // all variations 85 | $variations = array_values((array)$experimentRule->getVariationsMap()); 86 | foreach ($variations as $variation) 87 | { 88 | echo "[OptimizelyVariation] -- variation = { key: " . $variation->getKey() . ", . id: " . $variation->getId() . ", featureEnabled: " . $variation->getFeatureEnabled() . " }" . PHP_EOL; 89 | $variables = $variation->getVariablesMap(); 90 | foreach ($variables as $variable) 91 | { 92 | echo "[OptimizelyVariable] --- variable: " . $variable->getKey() . ", " . $variable->getId() . PHP_EOL; 93 | // use variable data here. 94 | } 95 | // use experimentRule data here. 96 | } 97 | } 98 | $deliveryRules = $flag->getDeliveryRules(); 99 | echo "------ Delivery rules -----" . PHP_EOL; 100 | foreach ($deliveryRules as $deliveryRule) 101 | { 102 | echo "---"; 103 | echo "[OptimizelyExperiment] - delivery rule-key = " . $deliveryRule->getKey() . PHP_EOL; 104 | echo "[OptimizelyExperiment] - delivery audiences = " . $deliveryRule->getExperimentAudiences() . PHP_EOL; 105 | 106 | // use delivery rule data here... 107 | } 108 | } 109 | // $optimizelyClient->notificationCenter->addNotificationListener( 110 | // NotificationType::OPTIMIZELY_CONFIG_UPDATE, 111 | // function () { 112 | // $newConfig = $optimizelyClient->getOptimizelyConfig(); 113 | // echo "[OptimizelyConfig] revision = " . $newConfig ? $newConfig->getRevision() : "" . PHP_EOL; 114 | // } 115 | // ); 116 | 117 | -------------------------------------------------------------------------------- /bug-bash/TrackEvent.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | namespace Optimizely\BugBash; 4 | 5 | require_once '../vendor/autoload.php'; 6 | require_once '../bug-bash/_bug-bash-autoload.php'; 7 | 8 | use Monolog\Logger; 9 | use Optimizely\Logger\DefaultLogger; 10 | use Optimizely\Notification\NotificationType; 11 | use Optimizely\Optimizely; 12 | use Optimizely\OptimizelyFactory; 13 | use Optimizely\OptimizelyUserContext; 14 | 15 | // 1. Change this SDK key to your project's SDK Key 16 | const SDK_KEY = '<your-sdk-key>'; 17 | 18 | // 2. Add an event to your project, adding it to your Experiment flag as a metric, then set the key here 19 | const EVENT_KEY = '<your-event-key>'; 20 | 21 | // 3. Uncomment each scenario 1 by 1 modifying the contents of the method 22 | // to test additional scenarios. 23 | 24 | $test = new TrackEventTests(); 25 | $test->checkTrackNotificationListenerProducesEvent(); 26 | // $test->checkConversionEventLogDispatchedOnTrackEvent(); 27 | // $test->checkConversionEventLogIsNOTDispatchedOnTrackEventForInvalidEventName(); 28 | // $test->testEventTagsShowInDispatchedEventAndAppOptimizelyCom(); 29 | 30 | // 4. Change the current folder into the bug-bash directory if you've not already 31 | // cd bug-bash/ 32 | 33 | // 5. Run the following command to execute the uncommented tests above: 34 | // php TrackEvent.php 35 | 36 | // https://docs.developers.optimizely.com/feature-experimentation/docs/track-event-php 37 | class TrackEventTests 38 | { 39 | // check that track notification listener produces event with event key 40 | public function checkTrackNotificationListenerProducesEvent(): void 41 | { 42 | $this->optimizelyClient->notificationCenter->addNotificationListener( 43 | NotificationType::TRACK, 44 | $this->onTrackEvent // ⬅️ This should be called with a valid EVENT_NAME 45 | ); 46 | 47 | // ...send track event. 48 | $this->userContext->trackEvent(EVENT_KEY); 49 | } 50 | 51 | // check that conversion event in the dispatch logs contains event key below 52 | public function checkConversionEventLogDispatchedOnTrackEvent(): void 53 | { 54 | $logger = new DefaultLogger(Logger::DEBUG); 55 | $localOptimizelyClient = new Optimizely(datafile: null, logger: $logger, sdkKey: SDK_KEY); 56 | $localUserContext = $localOptimizelyClient->createUserContext($this->userId); 57 | 58 | $localUserContext->trackEvent(EVENT_KEY); 59 | } 60 | 61 | // check that event is NOT dispatched if invalid event key is used 62 | // test changing event key in the UI and in the code 63 | public function checkConversionEventLogIsNOTDispatchedOnTrackEventForInvalidEventName(): void 64 | { 65 | $logger = new DefaultLogger(Logger::DEBUG); 66 | $localOptimizelyClient = new Optimizely(datafile: null, logger: $logger, sdkKey: SDK_KEY); 67 | $localUserContext = $localOptimizelyClient->createUserContext($this->userId); 68 | $this->optimizelyClient->notificationCenter->addNotificationListener( 69 | NotificationType::TRACK, 70 | $this->onTrackEvent // ⬅️ There should not be a Notification Listener OnTrackEvent called on invalid event name 71 | ); 72 | 73 | // You should not see any "Optimizely.DEBUG: Dispatching conversion event" but instead see 74 | // "Optimizely.INFO: Not tracking user "{user-id}" for event "an_invalid_event_name_not_in_the_project". 75 | $localUserContext->trackEvent("an_invalid_event_name_not_in_the_project"); 76 | } 77 | 78 | // try adding event tags (in the project and in the line below) and see if they show in the event body 79 | public function testEventTagsShowInDispatchedEventAndAppOptimizelyCom(): void 80 | { 81 | $logger = new DefaultLogger(Logger::DEBUG); 82 | $localOptimizelyClient = new Optimizely(datafile: null, logger: $logger, sdkKey: SDK_KEY); 83 | $localUserContext = $localOptimizelyClient->createUserContext($this->userId); 84 | $custom_tags = [ 85 | 'shoe_size_paris_points' => 44, 86 | 'shoe_size_us_size' => 11.5, 87 | 'use_us_size' => false, 88 | 'color' => 'blue' 89 | ]; 90 | 91 | // Dispatched event should have the tags added to the payload `params { ... }` and also 92 | // should show on app.optimizely.com Reports tab after 5-10 minutes 93 | $localUserContext->trackEvent(EVENT_KEY, $custom_tags); 94 | } 95 | 96 | private Optimizely $optimizelyClient; 97 | private string $userId; 98 | private ?OptimizelyUserContext $userContext; 99 | private string $outputTag = "Track Event"; 100 | private \Closure $onTrackEvent; 101 | 102 | public function __construct() 103 | { 104 | $this->optimizelyClient = OptimizelyFactory::createDefaultInstance(SDK_KEY); 105 | 106 | $this->userId = 'user-' . mt_rand(10, 99); 107 | $attributes = ['age' => 19, 'country' => 'bangledesh', 'has_purchased' => true]; 108 | $this->userContext = $this->optimizelyClient->createUserContext($this->userId, $attributes); 109 | 110 | $this->onTrackEvent = function ($type, $userId, $attributes, $decisionInfo) { 111 | print ">>> [$this->outputTag] OnTrackEvent: 112 | type: $type, 113 | userId: $userId, 114 | attributes: " . print_r($attributes, true) . " 115 | decisionInfo: " . print_r($decisionInfo, true) . "\r\n"; 116 | }; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /bug-bash/_bug-bash-autoload.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | function bug_bash_autoloader($class): void 4 | { 5 | $class_path = str_replace('\\', '/', $class); 6 | 7 | $file = dirname(__DIR__) . '/src/' . $class_path . '.php'; 8 | 9 | // if the file exists, require it 10 | if (file_exists($file)) { 11 | require $file; 12 | } 13 | } 14 | 15 | spl_autoload_register('bug_bash_autoloader'); 16 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "optimizely/optimizely-sdk", 3 | "description": "Optimizely PHP SDK for Optimizely Feature Experimentation, Optimizely Full Stack (legacy), and Optimizely Rollouts", 4 | "keywords": ["optimizely", "sdk"], 5 | "license": "Apache-2.0", 6 | "authors": [ 7 | { 8 | "name": "Optimizely", 9 | "email": "developers@optimizely.com" 10 | } 11 | ], 12 | "scripts": { 13 | "test": "phpunit", 14 | "lint": "phpcs", 15 | "beautify": "phpcbf" 16 | }, 17 | "require": { 18 | "php": ">=8.1", 19 | "guzzlehttp/guzzle": ">=6.2", 20 | "justinrainbow/json-schema": "^1.6 || ^2.0 || ^4.0 || ^5.0", 21 | "lastguest/murmurhash": "^1.3.0", 22 | "monolog/monolog": ">=1.21" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "^9.3", 26 | "php-coveralls/php-coveralls": "v2.5.3", 27 | "squizlabs/php_codesniffer": "3.7", 28 | "icecave/parity": "^3.0.1" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "Optimizely\\": "src/Optimizely" 33 | } 34 | }, 35 | "config": { 36 | "sort-packages": true 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0"?> 2 | <ruleset name="OptimizelyPSR2"> 3 | <!-- description for custom ruleset --> 4 | <description>A custom coding standard for Optimizely PHP-SDK based on PSR2</description> 5 | 6 | <!-- If no files or directories are specified on commandline, these files will be sniffed --> 7 | <file>./src</file> 8 | <file>./tests</file> 9 | 10 | <!-- Exclude patterns for files to be excluded from sniffing --> 11 | <!-- <exclude-pattern>./tests/EventTests/*</exclude-pattern> --> 12 | 13 | <!-- Embed command line arguments in config file. --> 14 | <arg name="tab-width" value="4"/> 15 | 16 | <!-- To exclude any rule sniff, get sniff name by running phpcs with -s switch --> 17 | <rule ref="PSR2"> 18 | <exclude name="Generic.Files.LineLength.TooLong"/> 19 | <exclude name="PSR2.Classes.PropertyDeclaration.Underscore"/> 20 | <exclude name="PSR1.Classes.ClassDeclaration.MultipleClasses"/> 21 | <exclude name="PSR1.Files.SideEffects.FoundWithSymbols"/> 22 | <exclude name="Generic.Files.LineEndings.InvalidEOLChar"/> 23 | </rule > 24 | </ruleset> 25 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | <phpunit 2 | colors="true" 3 | stderr="true" 4 | beStrictAboutTestsThatDoNotTestAnything="false" 5 | convertErrorsToExceptions="true" 6 | convertNoticesToExceptions="true" 7 | convertWarningsToExceptions="true" 8 | stopOnFailure="false" 9 | bootstrap="phpunit_bootstrap.php"> 10 | <testsuites> 11 | <testsuite name="Optimizely PHP SDK Tests"> 12 | <directory>tests</directory> 13 | </testsuite> 14 | </testsuites> 15 | <filter> 16 | <whitelist processUncoveredFilesFromWhitelist="true"> 17 | <directory suffix=".php">src/Optimizely</directory> 18 | </whitelist> 19 | </filter> 20 | <php> 21 | <ini name="memory_limit" value="256M"/> 22 | </php> 23 | </phpunit> 24 | -------------------------------------------------------------------------------- /src/Optimizely/Decide/OptimizelyDecideOption.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2021, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Decide; 19 | 20 | class OptimizelyDecideOption 21 | { 22 | const DISABLE_DECISION_EVENT = 'DISABLE_DECISION_EVENT'; 23 | const ENABLED_FLAGS_ONLY = 'ENABLED_FLAGS_ONLY'; 24 | const IGNORE_USER_PROFILE_SERVICE = 'IGNORE_USER_PROFILE_SERVICE'; 25 | const INCLUDE_REASONS = 'INCLUDE_REASONS'; 26 | const EXCLUDE_VARIABLES = 'EXCLUDE_VARIABLES'; 27 | } 28 | -------------------------------------------------------------------------------- /src/Optimizely/Decide/OptimizelyDecision.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2021, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Decide; 19 | 20 | class OptimizelyDecision implements \JsonSerializable 21 | { 22 | private $variationKey; 23 | private $enabled; 24 | private $variables; 25 | private $ruleKey; 26 | private $flagKey; 27 | private $userContext; 28 | private $reasons; 29 | 30 | 31 | public function __construct( 32 | $variationKey = null, 33 | $enabled = null, 34 | $variables = null, 35 | $ruleKey = null, 36 | $flagKey = null, 37 | $userContext = null, 38 | $reasons = null 39 | ) { 40 | $this->variationKey = $variationKey; 41 | $this->enabled = $enabled === null ? false : $enabled; 42 | $this->variables = $variables === null ? [] : $variables; 43 | $this->ruleKey = $ruleKey; 44 | $this->flagKey = $flagKey; 45 | $this->userContext = $userContext; 46 | $this->reasons = $reasons === null ? [] : $reasons; 47 | } 48 | 49 | public function getVariationKey() 50 | { 51 | return $this->variationKey; 52 | } 53 | 54 | public function getEnabled() 55 | { 56 | return $this->enabled; 57 | } 58 | 59 | public function getVariables() 60 | { 61 | return $this->variables; 62 | } 63 | 64 | public function getRuleKey() 65 | { 66 | return $this->ruleKey; 67 | } 68 | 69 | public function getFlagKey() 70 | { 71 | return $this->flagKey; 72 | } 73 | 74 | public function getUserContext() 75 | { 76 | return $this->userContext; 77 | } 78 | 79 | public function getReasons() 80 | { 81 | return $this->reasons; 82 | } 83 | 84 | #[\ReturnTypeWillChange] 85 | public function jsonSerialize() 86 | { 87 | return get_object_vars($this); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Optimizely/Decide/OptimizelyDecisionMessage.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2021, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Decide; 19 | 20 | class OptimizelyDecisionMessage 21 | { 22 | const SDK_NOT_READY = 'Optimizely SDK not configured properly yet.'; 23 | const FLAG_KEY_INVALID = 'No flag was found for key "%s".'; 24 | const VARIABLE_VALUE_INVALID = 'Variable value for key "%s" is invalid or wrong type.'; 25 | } 26 | -------------------------------------------------------------------------------- /src/Optimizely/DecisionService/FeatureDecision.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, 2019, 2021 Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\DecisionService; 18 | 19 | class FeatureDecision 20 | { 21 | const DECISION_SOURCE_FEATURE_TEST = 'feature-test'; 22 | const DECISION_SOURCE_ROLLOUT = 'rollout'; 23 | const DECISION_SOURCE_EXPERIMENT = 'experiment'; 24 | 25 | /** 26 | * The experiment in this decision. 27 | * 28 | * @var Experiment 29 | */ 30 | private $_experiment; 31 | 32 | /** 33 | * The variation in this decision. 34 | * 35 | * @var Variation 36 | */ 37 | private $_variation; 38 | 39 | /** 40 | * The source of the decision. Either DECISION_SOURCE_FEATURE_TEST or DECISION_SOURCE_ROLLOUT 41 | * 42 | * @var string 43 | */ 44 | private $_source; 45 | 46 | /** 47 | * Array of log messages that represent decision making. 48 | * 49 | * @var array 50 | */ 51 | private $reasons; 52 | 53 | /** 54 | * FeatureDecision constructor. 55 | * 56 | * @param $experiment 57 | * @param $variation 58 | * @param $source 59 | */ 60 | public function __construct($experiment, $variation, $source, array $reasons = []) 61 | { 62 | $this->_experiment = $experiment; 63 | $this->_variation = $variation; 64 | $this->_source = $source; 65 | $this->reasons = $reasons; 66 | } 67 | 68 | public function getExperiment() 69 | { 70 | return $this->_experiment; 71 | } 72 | 73 | public function getVariation() 74 | { 75 | return $this->_variation; 76 | } 77 | 78 | public function getSource() 79 | { 80 | return $this->_source; 81 | } 82 | 83 | public function getReasons() 84 | { 85 | return $this->reasons; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Optimizely/Entity/Attribute.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Entity; 19 | 20 | class Attribute 21 | { 22 | /** 23 | * @var string Attribute ID. 24 | */ 25 | private $_id; 26 | 27 | /** 28 | * @var string Attribute key. 29 | */ 30 | private $_key; 31 | 32 | 33 | public function __construct($id = null, $key = null) 34 | { 35 | $this->_id = $id; 36 | $this->_key = $key; 37 | } 38 | 39 | /** 40 | * @return string Get attribute ID. 41 | */ 42 | public function getId() 43 | { 44 | return $this->_id; 45 | } 46 | 47 | /** 48 | * @param $id string ID for attribute. 49 | */ 50 | public function setId($id) 51 | { 52 | $this->_id = $id; 53 | } 54 | 55 | /** 56 | * @return string Get attribute key. 57 | */ 58 | public function getKey() 59 | { 60 | return $this->_key; 61 | } 62 | 63 | /** 64 | * @param $key string Key for attribute. 65 | */ 66 | public function setKey($key) 67 | { 68 | $this->_key = $key; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Optimizely/Entity/Audience.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Entity; 19 | 20 | class Audience 21 | { 22 | /** 23 | * @var string Audience ID. 24 | */ 25 | private $_id; 26 | 27 | /** 28 | * @var string Audience name. 29 | */ 30 | private $_name; 31 | 32 | /** 33 | * @var string Audience conditions. 34 | */ 35 | private $_conditions; 36 | 37 | /** 38 | * @var array De-serialized audience conditions 39 | */ 40 | private $_conditionsList; 41 | 42 | 43 | public function __construct($id = null, $name = null, $conditions = null) 44 | { 45 | $this->_id = $id; 46 | $this->_name = $name; 47 | $this->_conditions = $conditions; 48 | } 49 | 50 | /** 51 | * @return string ID of audience. 52 | */ 53 | public function getId() 54 | { 55 | return $this->_id; 56 | } 57 | 58 | /** 59 | * @param $id string ID for audience. 60 | */ 61 | public function setId($id) 62 | { 63 | $this->_id = $id; 64 | } 65 | 66 | /** 67 | * @return string Audience name. 68 | */ 69 | public function getName() 70 | { 71 | return $this->_name; 72 | } 73 | 74 | /** 75 | * @param $name string Audience name 76 | */ 77 | public function setName($name) 78 | { 79 | $this->_name = $name; 80 | } 81 | 82 | /** 83 | * @return string Conditions building the audience. 84 | */ 85 | public function getConditions() 86 | { 87 | return $this->_conditions; 88 | } 89 | 90 | /** 91 | * @param $conditions string Audience conditions. 92 | */ 93 | public function setConditions($conditions) 94 | { 95 | $this->_conditions = $conditions; 96 | } 97 | 98 | /** 99 | * @return array De-serialized audience conditions. 100 | */ 101 | public function getConditionsList() 102 | { 103 | return $this->_conditionsList; 104 | } 105 | 106 | /** 107 | * @param $conditionsList array De-serialized audience conditions. 108 | */ 109 | public function setConditionsList($conditionsList) 110 | { 111 | $this->_conditionsList = $conditionsList; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/Optimizely/Entity/Event.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Entity; 19 | 20 | class Event 21 | { 22 | /** 23 | * @var string Event ID. 24 | */ 25 | private $_id; 26 | 27 | /** 28 | * @var string Event key. 29 | */ 30 | private $_key; 31 | 32 | /** 33 | * @var array Experiments using the event. 34 | */ 35 | private $_experimentIds; 36 | 37 | 38 | public function __construct($id = null, $key = null, $experimentIds = null) 39 | { 40 | $this->_id = $id; 41 | $this->_key = $key; 42 | $this->_experimentIds = $experimentIds; 43 | } 44 | 45 | /** 46 | * @return string ID of event. 47 | */ 48 | public function getId() 49 | { 50 | return $this->_id; 51 | } 52 | 53 | /** 54 | * @param $id string ID for event. 55 | */ 56 | public function setId($id) 57 | { 58 | $this->_id = $id; 59 | } 60 | 61 | /** 62 | * @return string Event key. 63 | */ 64 | public function getKey() 65 | { 66 | return $this->_key; 67 | } 68 | 69 | /** 70 | * @param $key string Key for event. 71 | */ 72 | public function setKey($key) 73 | { 74 | $this->_key = $key; 75 | } 76 | 77 | /** 78 | * @return array Experiments using event. 79 | */ 80 | public function getExperimentIds() 81 | { 82 | return $this->_experimentIds; 83 | } 84 | 85 | /** 86 | * @param $experimentIds array Experiments using event. 87 | */ 88 | public function setExperimentIds($experimentIds) 89 | { 90 | $this->_experimentIds = $experimentIds; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Optimizely/Entity/FeatureFlag.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Entity; 19 | 20 | use Optimizely\Utils\ConfigParser; 21 | 22 | class FeatureFlag 23 | { 24 | 25 | /** 26 | * variable to hold feature flag ID 27 | * 28 | * @var String 29 | */ 30 | private $_id; 31 | 32 | /** 33 | * variable to hold feature flag key 34 | * 35 | * @var String 36 | */ 37 | private $_key; 38 | 39 | /** 40 | * The ID of the rollout that is attached to this feature flag 41 | * 42 | * @var String 43 | */ 44 | private $_rolloutId; 45 | 46 | /** 47 | * A list of the IDs of the experiments the feature flag is attached to. If there are multiple expeirments, 48 | * they must be in the same mutually exclusive group. 49 | * 50 | * @var [String] 51 | */ 52 | private $_experimentIds; 53 | 54 | /** 55 | * A list of the feature variables that are part of this feature 56 | * 57 | * @var [FeatureVariable] 58 | */ 59 | private $_variables; 60 | 61 | public function __construct($id = null, $key = null, $rolloutId = null, $experimentIds = null, $variables = []) 62 | { 63 | $this->_id = $id; 64 | $this->_key = $key; 65 | $this->_rolloutId = $rolloutId; 66 | $this->_experimentIds = $experimentIds; 67 | $this->_variables = ConfigParser::generateMap($variables, null, FeatureVariable::class); 68 | } 69 | 70 | /** 71 | * @return String feature flag ID 72 | */ 73 | public function getId() 74 | { 75 | return $this->_id; 76 | } 77 | 78 | /** 79 | * @param String $id feature flag ID 80 | */ 81 | public function setId($id) 82 | { 83 | $this->_id = $id; 84 | } 85 | 86 | /** 87 | * @return String feature flag key 88 | */ 89 | public function getKey() 90 | { 91 | return $this->_key; 92 | } 93 | 94 | /** 95 | * @param String $key feature flag key 96 | */ 97 | public function setKey($key) 98 | { 99 | $this->_key = $key; 100 | } 101 | 102 | /** 103 | * @return String attached rollout ID 104 | */ 105 | public function getRolloutId() 106 | { 107 | return $this->_rolloutId; 108 | } 109 | 110 | /** 111 | * @param String $rolloutId attached rollout ID 112 | */ 113 | public function setRolloutId($rolloutId) 114 | { 115 | $this->_rolloutId = $rolloutId; 116 | } 117 | 118 | /** 119 | * @return [String] attached experiment IDs 120 | */ 121 | public function getExperimentIds() 122 | { 123 | return $this->_experimentIds; 124 | } 125 | 126 | /** 127 | * @param [String] $experimentIds attached experiment IDs 128 | */ 129 | public function setExperimentIds($experimentIds) 130 | { 131 | $this->_experimentIds = $experimentIds; 132 | } 133 | 134 | /** 135 | * @return [FeatureVariable] feature variables that are part of this feature 136 | */ 137 | public function getVariables() 138 | { 139 | return $this->_variables; 140 | } 141 | 142 | /** 143 | * @param [FeatureVariable] $variables feature variables that are part of this feature 144 | */ 145 | public function setVariables($variables) 146 | { 147 | $this->_variables = ConfigParser::generateMap($variables, null, FeatureVariable::class); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/Optimizely/Entity/FeatureVariable.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, 2019-2020 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Entity; 19 | 20 | class FeatureVariable 21 | { 22 | 23 | // Feature variable primitive types 24 | const BOOLEAN_TYPE = 'boolean'; 25 | const DOUBLE_TYPE = 'double'; 26 | const INTEGER_TYPE = 'integer'; 27 | const JSON_TYPE = 'json'; 28 | const STRING_TYPE = 'string'; 29 | 30 | /** 31 | * variable to hold the feature variable ID 32 | * 33 | * @var String 34 | */ 35 | private $_id; 36 | 37 | /** 38 | * variable to hold the feature variable key 39 | * 40 | * @var String 41 | */ 42 | private $_key; 43 | 44 | /** 45 | * variable denoting what primitive type the variable is. Will be one of 4 possible values: 46 | * a. boolean 47 | * b. string 48 | * c. integer 49 | * d. double 50 | * e. json 51 | * 52 | * @var String 53 | */ 54 | private $_type; 55 | 56 | /** 57 | * variable containing the string representation of the default value for the feature variable. 58 | * This is the variable value that should be returned if the user is not bucketed into any variations 59 | * or fails the audience rules. 60 | * 61 | * @var String 62 | */ 63 | private $_defaultValue; 64 | 65 | 66 | public function __construct($id = null, $key = null, $type = null, $defaultValue = null) 67 | { 68 | $this->_id = $id; 69 | $this->_key = $key; 70 | $this->_type = $type; 71 | $this->_defaultValue = $defaultValue; 72 | } 73 | 74 | /** 75 | * @return String Feature variable ID 76 | */ 77 | public function getId() 78 | { 79 | return $this->_id; 80 | } 81 | 82 | /** 83 | * @param String $id Feature variable ID 84 | */ 85 | public function setId($id) 86 | { 87 | $this->_id = $id; 88 | } 89 | 90 | /** 91 | * @return String Feature variable Key 92 | */ 93 | public function getKey() 94 | { 95 | return $this->_key; 96 | } 97 | 98 | /** 99 | * @param String $key Feature variable Key 100 | */ 101 | public function setKey($key) 102 | { 103 | $this->_key = $key; 104 | } 105 | 106 | /** 107 | * @return String Feature variable primitive type 108 | */ 109 | public function getType() 110 | { 111 | return $this->_type; 112 | } 113 | 114 | /** 115 | * @param String $type Feature variable primitive type 116 | */ 117 | public function setType($type) 118 | { 119 | $this->_type = $type; 120 | } 121 | 122 | /** 123 | * @return String Default value of the feature variable 124 | */ 125 | public function getDefaultValue() 126 | { 127 | return $this->_defaultValue; 128 | } 129 | 130 | /** 131 | * @param String $value Default value of the feature variable 132 | */ 133 | public function setDefaultValue($value) 134 | { 135 | $this->_defaultValue = $value; 136 | } 137 | 138 | /** 139 | * Returns feature variable method name based on 140 | * feature variable type. 141 | * 142 | * @param String $type Feature variable type. 143 | */ 144 | public static function getFeatureVariableMethodName($type) 145 | { 146 | switch ($type) { 147 | case FeatureVariable::BOOLEAN_TYPE: 148 | return "getFeatureVariableBoolean"; 149 | case FeatureVariable::DOUBLE_TYPE: 150 | return "getFeatureVariableDouble"; 151 | case FeatureVariable::INTEGER_TYPE: 152 | return "getFeatureVariableInteger"; 153 | case FeatureVariable::JSON_TYPE: 154 | return "getFeatureVariableJSON"; 155 | case FeatureVariable::STRING_TYPE: 156 | return "getFeatureVariableString"; 157 | default: 158 | return null; 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/Optimizely/Entity/Group.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Entity; 19 | 20 | use Optimizely\Utils\ConfigParser; 21 | 22 | class Group 23 | { 24 | /** 25 | * @var string Group ID. 26 | */ 27 | private $_id; 28 | 29 | /** 30 | * @var string Group policy. 31 | */ 32 | private $_policy; 33 | 34 | /** 35 | * @var array Experiments in the group. 36 | */ 37 | private $_experiments; 38 | 39 | /** 40 | * @var array Traffic allocation of experiments in the group. 41 | */ 42 | private $_trafficAllocation; 43 | 44 | 45 | public function __construct($id = null, $policy = null, $experiments = null, $trafficAllocation = null) 46 | { 47 | $this->_id = $id; 48 | $this->_policy = $policy; 49 | $this->_experiments = $experiments; 50 | $this->_trafficAllocation = $trafficAllocation; 51 | } 52 | 53 | /** 54 | * @return string ID of the group. 55 | */ 56 | public function getId() 57 | { 58 | return $this->_id; 59 | } 60 | 61 | /** 62 | * @param $id string ID for group. 63 | */ 64 | public function setId($id) 65 | { 66 | $this->_id = $id; 67 | } 68 | 69 | /** 70 | * @return string Policy of the group. 71 | */ 72 | public function getPolicy() 73 | { 74 | return $this->_policy; 75 | } 76 | 77 | /** 78 | * @param $policy string Policy for group. 79 | */ 80 | public function setPolicy($policy) 81 | { 82 | $this->_policy = $policy; 83 | } 84 | 85 | /** 86 | * @return array Experiments in the group. 87 | */ 88 | public function getExperiments() 89 | { 90 | return $this->_experiments; 91 | } 92 | 93 | /** 94 | * @param $experiments array Experiments in the group. 95 | */ 96 | public function setExperiments($experiments) 97 | { 98 | $this->_experiments = $experiments; 99 | } 100 | 101 | /** 102 | * @return array Traffic allocation of experiments in group. 103 | */ 104 | public function getTrafficAllocation() 105 | { 106 | return $this->_trafficAllocation; 107 | } 108 | 109 | /** 110 | * @param $trafficAllocation array Traffic allocation of experiments in group. 111 | */ 112 | public function setTrafficAllocation($trafficAllocation) 113 | { 114 | $this->_trafficAllocation = ConfigParser::generateMap($trafficAllocation, null, TrafficAllocation::class); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/Optimizely/Entity/Rollout.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Entity; 19 | 20 | use Optimizely\Utils\ConfigParser; 21 | 22 | class Rollout 23 | { 24 | 25 | /** 26 | * The ID of the rollout 27 | * 28 | * @var String 29 | */ 30 | private $_id; 31 | 32 | /** 33 | * A list of experiments representing the different rules of the rollout 34 | * 35 | * @var [Experiment] 36 | */ 37 | private $_experiments; 38 | 39 | public function __construct($id = null, $experiments = []) 40 | { 41 | $this->_id = $id; 42 | $this->_experiments = ConfigParser::generateMap($experiments, null, Experiment::class); 43 | } 44 | 45 | /** 46 | * @return String ID of the rollout 47 | */ 48 | public function getId() 49 | { 50 | return $this->_id; 51 | } 52 | 53 | /** 54 | * @param String $id ID of the rollout 55 | */ 56 | public function setId($id) 57 | { 58 | $this->_id = $id; 59 | } 60 | 61 | /** 62 | * @return [Experiments] A list of experiments representing the different rules of the rollout 63 | */ 64 | public function getExperiments() 65 | { 66 | return $this->_experiments; 67 | } 68 | 69 | /** 70 | * @param [Experiments] $experiments A list of experiments representing the different rules of the rollout 71 | */ 72 | public function setExperiments($experiments) 73 | { 74 | $this->_experiments = ConfigParser::generateMap($experiments, null, Experiment::class); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Optimizely/Entity/TrafficAllocation.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Entity; 19 | 20 | class TrafficAllocation 21 | { 22 | /** 23 | * @var string ID representing experiment or variation depending on parent. 24 | */ 25 | private $_entityId; 26 | 27 | /** 28 | * @var integer Value representing last bucket number for the experiment or variation. 29 | */ 30 | private $_endOfRange; 31 | 32 | public function __construct($entityId = null, $endOfRange = null) 33 | { 34 | $this->_entityId = $entityId; 35 | $this->_endOfRange = $endOfRange; 36 | } 37 | 38 | /** 39 | * @return string Entity ID representing experiment or variation. 40 | */ 41 | public function getEntityId() 42 | { 43 | return $this->_entityId; 44 | } 45 | 46 | /** 47 | * @param $entityId string ID of experiment or group. 48 | */ 49 | public function setEntityId($entityId) 50 | { 51 | $this->_entityId = $entityId; 52 | } 53 | 54 | /** 55 | * @return integer End of range for experiment or variation. 56 | */ 57 | public function getEndOfRange() 58 | { 59 | return $this->_endOfRange; 60 | } 61 | 62 | /** 63 | * @param $endOfRange integer End of range for experiment or variation. 64 | */ 65 | public function setEndOfRange($endOfRange) 66 | { 67 | $this->_endOfRange = $endOfRange; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Optimizely/Entity/VariableUsage.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Entity; 19 | 20 | class VariableUsage 21 | { 22 | 23 | /** 24 | * The ID of the live variable this usage is modifying 25 | * 26 | * @var String 27 | */ 28 | private $_id; 29 | 30 | /** 31 | * the variable value for users in this particular variation 32 | * 33 | * @var String 34 | */ 35 | private $_value; 36 | 37 | public function __construct($id = null, $value = null) 38 | { 39 | $this->_id = $id; 40 | $this->_value = $value; 41 | } 42 | 43 | /** 44 | * @return String ID of the live variable this usage is modifying 45 | */ 46 | public function getId() 47 | { 48 | return $this->_id; 49 | } 50 | 51 | /** 52 | * @param String $id ID of the live variable this usage is modifying 53 | */ 54 | public function setId($id) 55 | { 56 | $this->_id = $id; 57 | } 58 | 59 | /** 60 | * @return String variable value for users in this particular variation 61 | */ 62 | public function getValue() 63 | { 64 | return $this->_value; 65 | } 66 | 67 | /** 68 | * @param String $value variable value for users in this particular variation 69 | */ 70 | public function setValue($value) 71 | { 72 | $this->_value = $value; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Optimizely/Entity/Variation.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016-2020, 2023 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Entity; 19 | 20 | use Optimizely\Utils\ConfigParser; 21 | 22 | class Variation 23 | { 24 | /** 25 | * @var string ID representing the variation. 26 | */ 27 | private $_id; 28 | 29 | /** 30 | * @var string Unique key of the variation. 31 | */ 32 | private $_key; 33 | 34 | /** 35 | * list of all VariableUsage instances that are part of this variation. 36 | * 37 | * @var [VariableUsage] 38 | */ 39 | private $_variableUsageInstances; 40 | 41 | /** 42 | * map of Feature Variable IDs to Variable Usages constructed during the initialization 43 | * of Variation objects from the list of Variable Usages. 44 | * 45 | * @var <String, VariableUsage> associative array 46 | */ 47 | private $_variableIdToVariableUsageInstanceMap; 48 | 49 | /** 50 | * @var mixed|null 51 | */ 52 | private mixed $_featureEnabled; 53 | 54 | public function __construct($id = null, $key = null, $featureEnabled = null, $variableUsageInstances = []) 55 | { 56 | $this->_id = $id; 57 | $this->_key = $key; 58 | $this->_featureEnabled = $featureEnabled; 59 | 60 | $this->_variableUsageInstances = ConfigParser::generateMap($variableUsageInstances, null, VariableUsage::class); 61 | 62 | $this->generateVariableIdToVariableUsageMap(); 63 | } 64 | 65 | /** 66 | * @return string Variation ID. 67 | */ 68 | public function getId() 69 | { 70 | return $this->_id; 71 | } 72 | 73 | /** 74 | * @param $id string ID for variation. 75 | */ 76 | public function setId($id) 77 | { 78 | $this->_id = $id; 79 | } 80 | 81 | /** 82 | * @return string Variation key. 83 | */ 84 | public function getKey() 85 | { 86 | return $this->_key; 87 | } 88 | 89 | /** 90 | * @param $key string Key for variation. 91 | */ 92 | public function setKey($key) 93 | { 94 | $this->_key = $key; 95 | } 96 | 97 | /** 98 | * @return boolean featureEnabled property 99 | */ 100 | public function getFeatureEnabled() 101 | { 102 | return $this->_featureEnabled; 103 | } 104 | 105 | /** 106 | * @param boolean $flag 107 | */ 108 | public function setFeatureEnabled($flag) 109 | { 110 | $this->_featureEnabled = $flag; 111 | } 112 | 113 | /** 114 | * @return [VariableUsage] Variable usage instances in this variation 115 | */ 116 | public function getVariables() 117 | { 118 | return $this->_variableUsageInstances; 119 | } 120 | 121 | /** 122 | * @param string Variable ID 123 | * 124 | * @return VariableUsage Variable usage instance corresponding to given variable ID 125 | */ 126 | public function getVariableUsageById($variableId) 127 | { 128 | return $this->_variableIdToVariableUsageInstanceMap[$variableId] ?? null; 129 | } 130 | 131 | /** 132 | * @param [VariableUsage] array of variable usage instances 133 | */ 134 | public function setVariables($variableUsageInstances) 135 | { 136 | $this->_variableUsageInstances = ConfigParser::generateMap($variableUsageInstances, null, VariableUsage::class); 137 | $this->generateVariableIdToVariableUsageMap(); 138 | } 139 | 140 | /** 141 | * Generates variable ID to Variable usage instance map 142 | * from variable usage instances 143 | */ 144 | private function generateVariableIdToVariableUsageMap() 145 | { 146 | if (!empty($this->_variableUsageInstances)) { 147 | foreach ($this->_variableUsageInstances as $variableUsage) { 148 | $this->_variableIdToVariableUsageInstanceMap[$variableUsage->getId()] = $variableUsage; 149 | } 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/Optimizely/Enums/CommonAudienceEvaluationLogs.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2019-2020, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Enums; 19 | 20 | class CommonAudienceEvaluationLogs 21 | { 22 | const AUDIENCE_EVALUATION_RESULT = "Audience \"%s\" evaluated to %s."; 23 | const ATTRIBUTE_FORMAT_INVALID = "Provided attributes are in an invalid format."; 24 | const EVALUATING_AUDIENCE = "Starting to evaluate audience \"%s\" with conditions: %s."; 25 | const INFINITE_ATTRIBUTE_VALUE = "Audience condition %s evaluated to UNKNOWN because the number value for user attribute \"%s\" is not in the range [-2^53, +2^53]."; 26 | const MISSING_ATTRIBUTE_VALUE = "Audience condition %s evaluated to UNKNOWN because no value was passed for user attribute \"%s\"."; 27 | const NULL_ATTRIBUTE_VALUE = "Audience condition %s evaluated to UNKNOWN because a null value was passed for user attribute \"%s\"."; 28 | const UNEXPECTED_TYPE = "Audience condition %s evaluated to UNKNOWN because a value of type \"%s\" was passed for user attribute \"%s\"."; 29 | 30 | const UNKNOWN_CONDITION_TYPE = "Audience condition %s uses an unknown condition type. You may need to upgrade to a newer release of the Optimizely SDK."; 31 | const UNKNOWN_CONDITION_VALUE = "Audience condition %s has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."; 32 | const UNKNOWN_MATCH_TYPE = "Audience condition %s uses an unknown match type. You may need to upgrade to a newer release of the Optimizely SDK."; 33 | } 34 | -------------------------------------------------------------------------------- /src/Optimizely/Enums/ControlAttributes.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2018, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Enums; 19 | 20 | class ControlAttributes 21 | { 22 | const BOT_FILTERING = "\$opt_bot_filtering"; 23 | const BUCKETING_ID = "\$opt_bucketing_id"; 24 | const USER_AGENT = "\$opt_user_agent"; 25 | } 26 | -------------------------------------------------------------------------------- /src/Optimizely/Enums/DecisionNotificationTypes.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2019-2021 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Enums; 19 | 20 | class DecisionNotificationTypes 21 | { 22 | const AB_TEST = "ab-test"; 23 | const ALL_FEATURE_VARIABLES = "all-feature-variables"; 24 | const FEATURE = "feature"; 25 | const FEATURE_TEST = "feature-test"; 26 | const FEATURE_VARIABLE = "feature-variable"; 27 | const FLAG = "flag"; 28 | } 29 | -------------------------------------------------------------------------------- /src/Optimizely/Enums/ExperimentAudienceEvaluationLogs.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2020, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Enums; 19 | 20 | class ExperimentAudienceEvaluationLogs extends CommonAudienceEvaluationLogs 21 | { 22 | const AUDIENCE_EVALUATION_RESULT_COMBINED = "Audiences for experiment \"%s\" collectively evaluated to %s."; 23 | const EVALUATING_AUDIENCES_COMBINED = "Evaluating audiences for experiment \"%s\": %s."; 24 | } 25 | -------------------------------------------------------------------------------- /src/Optimizely/Enums/ProjectConfigManagerConstants.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2019-2020, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Enums; 19 | 20 | class ProjectConfigManagerConstants 21 | { 22 | /** 23 | * @const int Time in seconds to wait before timing out. 24 | */ 25 | const TIMEOUT = 10; 26 | 27 | /** 28 | * @const String Default URL Template to use if only SDK key is provided. 29 | */ 30 | const DEFAULT_DATAFILE_URL_TEMPLATE = "https://cdn.optimizely.com/datafiles/%s.json"; 31 | 32 | /** 33 | * @const String Default URL Template to use if Access token is provided along with the SDK key. 34 | */ 35 | const AUTHENTICATED_DATAFILE_URL_TEMPLATE = "https://config.optimizely.com/datafiles/auth/%s.json"; 36 | 37 | /** 38 | * @const String to use while fetching the datafile. 39 | */ 40 | const IF_MODIFIED_SINCE = "If-Modified-Since"; 41 | 42 | /** 43 | * @const String to use while handling the response. 44 | */ 45 | const LAST_MODIFIED = "Last-Modified"; 46 | } 47 | -------------------------------------------------------------------------------- /src/Optimizely/Enums/RolloutAudienceEvaluationLogs.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2020, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Enums; 19 | 20 | class RolloutAudienceEvaluationLogs extends CommonAudienceEvaluationLogs 21 | { 22 | const AUDIENCE_EVALUATION_RESULT_COMBINED = "Audiences for rule %s collectively evaluated to %s."; 23 | const EVALUATING_AUDIENCES_COMBINED = "Evaluating audiences for rule %s: %s."; 24 | } 25 | -------------------------------------------------------------------------------- /src/Optimizely/ErrorHandler/DefaultErrorHandler.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\ErrorHandler; 18 | 19 | use Exception; 20 | 21 | class DefaultErrorHandler implements ErrorHandlerInterface 22 | { 23 | public function handleError(Exception $error) 24 | { 25 | throw $error; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Optimizely/ErrorHandler/ErrorHandlerInterface.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\ErrorHandler; 18 | 19 | use Exception; 20 | 21 | /** 22 | * Interface ErrorHandlerInterface 23 | * 24 | * @package Optimizely\ErrorHandler 25 | */ 26 | interface ErrorHandlerInterface 27 | { 28 | public function handleError(Exception $error); 29 | } 30 | -------------------------------------------------------------------------------- /src/Optimizely/ErrorHandler/NoOpErrorHandler.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\ErrorHandler; 18 | 19 | use Exception; 20 | 21 | /** 22 | * Class NoOpErrorHandler 23 | * 24 | * @package Optimizely\ErrorHandler 25 | */ 26 | class NoOpErrorHandler implements ErrorHandlerInterface 27 | { 28 | public function handleError(Exception $error) 29 | { 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Optimizely/Event/Builder/Params.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016-2019, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | define('ACCOUNT_ID', 'account_id'); 19 | define('ACTIVATE_EVENT_KEY', 'campaign_activated'); 20 | define('ANONYMIZE_IP', 'anonymize_ip'); 21 | define('ATTRIBUTES', 'attributes'); 22 | define('CAMPAIGN_ID', 'campaign_id'); 23 | define('CLIENT_ENGINE', 'client_name'); 24 | define('CLIENT_VERSION', 'client_version'); 25 | define('CUSTOM_ATTRIBUTE_FEATURE_TYPE', 'custom'); 26 | define('DECISIONS', 'decisions'); 27 | define('ENRICH_DECISIONS', 'enrich_decisions'); 28 | define('ENTITY_ID', 'entity_id'); 29 | define('EVENTS', 'events'); 30 | define('EXPERIMENT_ID', 'experiment_id'); 31 | define('KEY', 'key'); 32 | define('PROJECT_ID', 'project_id'); 33 | define('REVISION', 'revision'); 34 | define('SNAPSHOTS', 'snapshots'); 35 | define('TIMESTAMP', 'timestamp'); 36 | define('TYPE', 'type'); 37 | define('UUID', 'uuid'); 38 | define('VALUE', 'value'); 39 | define('VARIATION_ID', 'variation_id'); 40 | define('VISITOR_ID', 'visitor_id'); 41 | define('VISITORS', 'visitors'); 42 | define('METADATA', 'metadata'); 43 | define('FLAG_KEY', 'flag_key'); 44 | define('RULE_KEY', 'rule_key'); 45 | define('RULE_TYPE', 'rule_type'); 46 | define('VARIATION_KEY', 'variation_key'); 47 | define('ENABLED', 'enabled'); 48 | -------------------------------------------------------------------------------- /src/Optimizely/Event/Dispatcher/DefaultEventDispatcher.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Event\Dispatcher; 18 | 19 | use GuzzleHttp\Client as HttpClient; 20 | use Optimizely\Event\LogEvent; 21 | 22 | /** 23 | * Class DefaultEventDispatcher 24 | * 25 | * @package Optimizely\Event\Dispatcher 26 | */ 27 | class DefaultEventDispatcher implements EventDispatcherInterface 28 | { 29 | /** 30 | * @const int Time in seconds to wait before timing out. 31 | */ 32 | const TIMEOUT = 10; 33 | 34 | /** 35 | * @var \GuzzleHttp\Client Guzzle HTTP client to send requests. 36 | */ 37 | private $httpClient; 38 | 39 | public function __construct(HttpClient $httpClient = null) 40 | { 41 | $this->httpClient = $httpClient ?: new HttpClient(); 42 | } 43 | 44 | public function dispatchEvent(LogEvent $event) 45 | { 46 | $options = [ 47 | 'headers' => $event->getHeaders(), 48 | 'json' => $event->getParams(), 49 | 'timeout' => DefaultEventDispatcher::TIMEOUT, 50 | 'connect_timeout' => DefaultEventDispatcher::TIMEOUT 51 | ]; 52 | 53 | $this->httpClient->request($event->getHttpVerb(), $event->getUrl(), $options); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Optimizely/Event/Dispatcher/EventDispatcherInterface.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Event\Dispatcher; 18 | 19 | use Optimizely\Event\LogEvent; 20 | 21 | /** 22 | * Interface EventDispatcherInterface 23 | * 24 | * @package Optimizely\Event\Dispatcher 25 | */ 26 | interface EventDispatcherInterface 27 | { 28 | public function dispatchEvent(LogEvent $event); 29 | } 30 | -------------------------------------------------------------------------------- /src/Optimizely/Event/LogEvent.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Event; 19 | 20 | class LogEvent 21 | { 22 | /** 23 | * @var string URL to dispatch log event to. 24 | */ 25 | private $_url; 26 | 27 | /** 28 | * @var array Parameters to be set in the log event. 29 | */ 30 | private $_params; 31 | 32 | /** 33 | * @var string HTTP verb to be used when dispatching the log event. 34 | */ 35 | private $_httpVerb; 36 | 37 | /** 38 | * @var array Headers to be set when sending the request. 39 | */ 40 | private $_headers; 41 | 42 | /** 43 | * LogEvent constructor. 44 | * 45 | * @param $url 46 | * @param $params 47 | * @param $httpVerb 48 | * @param $headers 49 | */ 50 | public function __construct($url, $params, $httpVerb, $headers) 51 | { 52 | $this->_url = $url; 53 | $this->_params = $params; 54 | $this->_httpVerb = $httpVerb; 55 | $this->_headers = $headers; 56 | } 57 | 58 | /** 59 | * @return string The URL to dispatch the request to. 60 | */ 61 | public function getUrl() 62 | { 63 | return $this->_url; 64 | } 65 | 66 | /** 67 | * @return array The parameters to send with the request. 68 | */ 69 | public function getParams() 70 | { 71 | return $this->_params; 72 | } 73 | 74 | /** 75 | * @return string HTTP verb to be used when dispatching the request. 76 | */ 77 | public function getHttpVerb() 78 | { 79 | return $this->_httpVerb; 80 | } 81 | 82 | /** 83 | * @return array The headers to set for the request. 84 | */ 85 | public function getHeaders() 86 | { 87 | return $this->_headers; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidAttributeException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidAttributeException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidAudienceException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidAudienceException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidCallbackArgumentCountException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidCallbackArgumentCountException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidDatafileVersionException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2018, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidDatafileVersionException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidEventException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidEventException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidEventTagException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidEventTagException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidExperimentException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidExperimentException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidFeatureFlagException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidFeatureFlagException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidFeatureVariableException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidFeatureVariableException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidGroupException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidGroupException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidInputException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidInputException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidNotificationTypeException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidNotificationTypeException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidRolloutException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidRolloutException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/InvalidVariationException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | class InvalidVariationException extends OptimizelyException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Optimizely/Exceptions/OptimizelyException.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Exceptions; 19 | 20 | use Exception; 21 | 22 | /** 23 | * Class OptimizelyException 24 | * 25 | * @package Optimizely\Exceptions 26 | */ 27 | class OptimizelyException extends Exception 28 | { 29 | } 30 | -------------------------------------------------------------------------------- /src/Optimizely/Logger/DefaultLogger.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, 2018-2019 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Logger; 18 | 19 | use Monolog\Logger; 20 | use Monolog\Formatter\LineFormatter; 21 | use Monolog\Handler\StreamHandler; 22 | 23 | /** 24 | * Class DefaultLogger 25 | * 26 | * @package Optimizely\Logger 27 | */ 28 | class DefaultLogger implements LoggerInterface 29 | { 30 | /** 31 | * @var Logger Logger instance. 32 | */ 33 | private $logger; 34 | 35 | /** 36 | * DefaultLogger constructor. 37 | * 38 | * @param int $minLevel Minimum level of messages to be logged. 39 | * @param string $stream The PHP stream to log output. 40 | */ 41 | public function __construct($minLevel = Logger::INFO, $stream = "stdout") 42 | { 43 | $formatter = new LineFormatter("[%datetime%] %channel%.%level_name%: %message%\n"); 44 | $streamHandler = new StreamHandler("php://{$stream}", $minLevel); 45 | $streamHandler->setFormatter($formatter); 46 | $this->logger = new Logger('Optimizely'); 47 | $this->logger->pushHandler($streamHandler); 48 | } 49 | 50 | public function log($logLevel, $logMessage) 51 | { 52 | $this->logger->log($logLevel, $logMessage); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Optimizely/Logger/LoggerInterface.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Logger; 18 | 19 | /** 20 | * Interface LoggerInterface 21 | * 22 | * @package Optimizely\Logger 23 | */ 24 | interface LoggerInterface 25 | { 26 | public function log($logLevel, $logMessage); 27 | } 28 | -------------------------------------------------------------------------------- /src/Optimizely/Logger/NoOpLogger.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Logger; 18 | 19 | /** 20 | * Class NoOpLogger 21 | * 22 | * @package Optimizely\Logger 23 | */ 24 | class NoOpLogger implements LoggerInterface 25 | { 26 | public function log($logLevel, $logMessage) 27 | { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Optimizely/Notification/NotificationType.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, 2019, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Notification; 18 | 19 | class NotificationType 20 | { 21 | /* 22 | * Notification triggered when an impression event is sent to Optimizely. 23 | * 24 | * @deprecated since 3.1.0 25 | */ 26 | const ACTIVATE = "ACTIVATE:experiment, user_id, attributes, variation, event"; 27 | 28 | /* 29 | * Notification triggered when a decision is made in 30 | * the system i.e. user activation, feature access 31 | * or feature-variable value is retrieved. 32 | */ 33 | const DECISION = "DECISION:type, user_id, attributes, decision_info"; 34 | 35 | /* 36 | * Notification triggered when Project Config is updated. 37 | */ 38 | const OPTIMIZELY_CONFIG_UPDATE = "OPTIMIZELY_CONFIG_UPDATE"; 39 | 40 | /* 41 | * Notification triggered when a conversion event is sent to Optimizely. 42 | */ 43 | const TRACK = "TRACK:event_key, user_id, attributes, event_tags, event"; 44 | 45 | public static function isNotificationTypeValid($notification_type) 46 | { 47 | $oClass = new \ReflectionClass(__CLASS__); 48 | $notificationTypeList = array_values($oClass->getConstants()); 49 | 50 | return in_array($notification_type, $notificationTypeList); 51 | } 52 | 53 | public static function getAll() 54 | { 55 | $oClass = new \ReflectionClass(__CLASS__); 56 | return $oClass->getConstants(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Optimizely/OptimizelyConfig/OptimizelyAttribute.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2021, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\OptimizelyConfig; 18 | 19 | class OptimizelyAttribute implements \JsonSerializable 20 | { 21 | /** 22 | * @var string id representing attribute. 23 | */ 24 | private $id; 25 | 26 | /** 27 | * @var string key representing attribute. 28 | */ 29 | private $key; 30 | 31 | public function __construct($id, $key) 32 | { 33 | $this->id = $id; 34 | $this->key = $key; 35 | } 36 | 37 | /** 38 | * @return string attribute id. 39 | */ 40 | public function getId() 41 | { 42 | return $this->id; 43 | } 44 | 45 | /** 46 | * @return string attribute key. 47 | */ 48 | public function getKey() 49 | { 50 | return $this->key; 51 | } 52 | 53 | /** 54 | * @return string JSON representation of the object. 55 | */ 56 | #[\ReturnTypeWillChange] 57 | public function jsonSerialize() 58 | { 59 | return get_object_vars($this); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Optimizely/OptimizelyConfig/OptimizelyAudience.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2021, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\OptimizelyConfig; 18 | 19 | class OptimizelyAudience implements \JsonSerializable 20 | { 21 | /** 22 | * @var string representing audience id. 23 | */ 24 | private $id; 25 | 26 | /** 27 | * @var string representing audience name . 28 | */ 29 | private $name; 30 | 31 | /** 32 | * @var string conditions representing audience conditions. 33 | */ 34 | private $conditions; 35 | 36 | 37 | public function __construct($id, $name, $conditions) 38 | { 39 | $this->id = $id; 40 | $this->name = $name; 41 | $this->conditions = $conditions; 42 | } 43 | 44 | /** 45 | * @return string audience id. 46 | */ 47 | public function getId() 48 | { 49 | return $this->id; 50 | } 51 | 52 | /** 53 | * @return string audience name. 54 | */ 55 | public function getName() 56 | { 57 | return $this->name; 58 | } 59 | 60 | /** 61 | * @return string audience conditions. 62 | */ 63 | public function getConditions() 64 | { 65 | return $this->conditions; 66 | } 67 | 68 | /** 69 | * @return string JSON representation of the object. 70 | */ 71 | #[\ReturnTypeWillChange] 72 | public function jsonSerialize() 73 | { 74 | return get_object_vars($this); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Optimizely/OptimizelyConfig/OptimizelyConfig.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2020-2021, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\OptimizelyConfig; 18 | 19 | class OptimizelyConfig implements \JsonSerializable 20 | { 21 | /** 22 | * @var string environmentKey of the config. 23 | */ 24 | private $environmentKey; 25 | 26 | /** 27 | * @var string sdkKey of the config. 28 | */ 29 | private $sdkKey; 30 | 31 | /** 32 | * @var string Revision of the config. 33 | */ 34 | private $revision; 35 | 36 | /** 37 | * Map of Experiment Keys to OptimizelyExperiments. 38 | * This experimentsMap is for experiments of legacy projects only. 39 | * For flag projects, experiment keys are not guaranteed to be unique 40 | * across multiple flags, so this map may not include all experiments 41 | * when keys conflict. Use experimentRules and deliveryRules instead. 42 | * 43 | * @var <String, OptimizelyExperiment> associative array 44 | */ 45 | private $experimentsMap; 46 | 47 | /** 48 | * Map of Feature Keys to OptimizelyFeatures. 49 | * 50 | * @var <String, OptimizelyFeature> associative array 51 | */ 52 | private $featuresMap; 53 | 54 | /** 55 | * Array of attributes as OptimizelyAttribute. 56 | * 57 | * @var [OptimizelyAttribute] 58 | */ 59 | private $attributes; 60 | 61 | /** 62 | * Array of audiences as OptimizelyAudience. 63 | * 64 | * @var [OptimizelyAudience] 65 | */ 66 | private $audiences; 67 | 68 | /** 69 | * Array of events as OptimizelyEvent. 70 | * 71 | * @var [OptimizelyEvent] 72 | */ 73 | private $events; 74 | 75 | /** 76 | * @var string Contents of datafile. 77 | */ 78 | private $datafile; 79 | 80 | 81 | public function __construct($revision, array $experimentsMap, array $featuresMap, $datafile = null, $environmentKey = '', $sdkKey = '', $attributes = [], $audiences = [], $events = []) 82 | { 83 | $this->environmentKey = $environmentKey; 84 | $this->sdkKey = $sdkKey; 85 | $this->revision = $revision; 86 | $this->experimentsMap = $experimentsMap; 87 | $this->featuresMap = $featuresMap; 88 | $this->attributes = $attributes; 89 | $this->audiences = $audiences; 90 | $this->events = $events; 91 | $this->datafile = $datafile; 92 | } 93 | 94 | /** 95 | * @return string Config environmentKey. 96 | */ 97 | public function getEnvironmentKey() 98 | { 99 | return $this->environmentKey; 100 | } 101 | 102 | /** 103 | * @return string Config sdkKey. 104 | */ 105 | public function getSdkKey() 106 | { 107 | return $this->sdkKey; 108 | } 109 | 110 | /** 111 | * @return string Config revision. 112 | */ 113 | public function getRevision() 114 | { 115 | return $this->revision; 116 | } 117 | 118 | /** 119 | * @return string Datafile contents. 120 | */ 121 | public function getDatafile() 122 | { 123 | return $this->datafile; 124 | } 125 | 126 | /** 127 | * @return array Map of Experiment Keys to OptimizelyExperiments. 128 | */ 129 | public function getExperimentsMap() 130 | { 131 | return $this->experimentsMap; 132 | } 133 | 134 | /** 135 | * @return array Map of Feature Keys to OptimizelyFeatures. 136 | */ 137 | public function getFeaturesMap() 138 | { 139 | return $this->featuresMap; 140 | } 141 | 142 | /** 143 | * @return array Attributes as OptimizelyAttribute. 144 | */ 145 | public function getAttributes() 146 | { 147 | return $this->attributes; 148 | } 149 | 150 | /** 151 | * @return array Audiences as OptimizelyAudience. 152 | */ 153 | public function getAudiences() 154 | { 155 | return $this->audiences; 156 | } 157 | 158 | /** 159 | * @return array Events as OptimizelyEvent. 160 | */ 161 | public function getEvents() 162 | { 163 | return $this->events; 164 | } 165 | 166 | /** 167 | * @return string JSON representation of the object. 168 | */ 169 | #[\ReturnTypeWillChange] 170 | public function jsonSerialize() 171 | { 172 | return get_object_vars($this); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/Optimizely/OptimizelyConfig/OptimizelyEvent.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2021, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\OptimizelyConfig; 18 | 19 | class OptimizelyEvent implements \JsonSerializable 20 | { 21 | /** 22 | * @var string id representing event. 23 | */ 24 | private $id; 25 | 26 | /** 27 | * @var string key representing event. 28 | */ 29 | private $key; 30 | 31 | /** 32 | * @var array experimentIds representing event experiment ids. 33 | */ 34 | private $experimentIds; 35 | 36 | 37 | public function __construct($id, $key, array $experimentIds) 38 | { 39 | $this->id = $id; 40 | $this->key = $key; 41 | $this->experimentIds = $experimentIds; 42 | } 43 | 44 | /** 45 | * @return string event ID. 46 | */ 47 | public function getId() 48 | { 49 | return $this->id; 50 | } 51 | 52 | /** 53 | * @return string event Key. 54 | */ 55 | public function getKey() 56 | { 57 | return $this->key; 58 | } 59 | 60 | /** 61 | * @return array experimentIds representing event experiment ids. 62 | */ 63 | public function getExperimentIds() 64 | { 65 | return $this->experimentIds; 66 | } 67 | 68 | /** 69 | * @return string JSON representation of the object. 70 | */ 71 | #[\ReturnTypeWillChange] 72 | public function jsonSerialize() 73 | { 74 | return get_object_vars($this); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Optimizely/OptimizelyConfig/OptimizelyExperiment.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2020-2021, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\OptimizelyConfig; 18 | 19 | class OptimizelyExperiment implements \JsonSerializable 20 | { 21 | /** 22 | * @var string ID representing Experiment. 23 | */ 24 | private $id; 25 | 26 | /** 27 | * @var string Key representing Experiment. 28 | */ 29 | private $key; 30 | 31 | /** 32 | * @var string string representing Experiment audience conditions name mapped. 33 | */ 34 | private $audiences; 35 | 36 | /** 37 | * Map of Variation Keys to OptimizelyVariations. 38 | * 39 | * @var <String, OptimizelyVariation> associative array 40 | */ 41 | private $variationsMap; 42 | 43 | public function __construct($id, $key, array $variationsMap, $audiences) 44 | { 45 | $this->id = $id; 46 | $this->key = $key; 47 | $this->audiences = $audiences; 48 | $this->variationsMap = $variationsMap; 49 | } 50 | 51 | /** 52 | * @return string Experiment ID. 53 | */ 54 | public function getId() 55 | { 56 | return $this->id; 57 | } 58 | 59 | /** 60 | * @return string Experiment key. 61 | */ 62 | public function getKey() 63 | { 64 | return $this->key; 65 | } 66 | 67 | /** 68 | * @return string Experiment audiences. 69 | */ 70 | public function getExperimentAudiences() 71 | { 72 | return $this->audiences; 73 | } 74 | 75 | /** 76 | * @return array Map of Variation Keys to OptimizelyVariations. 77 | */ 78 | public function getVariationsMap() 79 | { 80 | return $this->variationsMap; 81 | } 82 | 83 | /** 84 | * @return string JSON representation of the object. 85 | */ 86 | #[\ReturnTypeWillChange] 87 | public function jsonSerialize() 88 | { 89 | return get_object_vars($this); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Optimizely/OptimizelyConfig/OptimizelyFeature.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2020-2021, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\OptimizelyConfig; 18 | 19 | class OptimizelyFeature implements \JsonSerializable 20 | { 21 | /** 22 | * @var string ID representing the feature. 23 | */ 24 | private $id; 25 | 26 | /** 27 | * @var string Key representing the feature. 28 | */ 29 | private $key; 30 | 31 | /** 32 | * Array of experiment rules. 33 | * 34 | * @var [OptimizelyExperiment] 35 | */ 36 | private $experimentRules; 37 | 38 | /** 39 | * Array of delivery rules. 40 | * 41 | * @var [OptimizelyExperiment] 42 | */ 43 | private $deliveryRules; 44 | 45 | /** 46 | * Map of Experiment Keys to OptimizelyExperiments. 47 | * 48 | * @var <String, OptimizelyExperiment> associative array 49 | */ 50 | private $experimentsMap; 51 | 52 | /** 53 | * Map of Variable Keys to OptimizelyVariables. 54 | * 55 | * @var <String, OptimizelyVariable> associative array 56 | */ 57 | private $variablesMap; 58 | 59 | public function __construct($id, $key, array $experimentsMap, array $variablesMap, array $experimentRules, array $deliveryRules) 60 | { 61 | $this->id = $id; 62 | $this->key = $key; 63 | $this->experimentRules = $experimentRules; 64 | $this->deliveryRules = $deliveryRules; 65 | $this->experimentsMap = $experimentsMap; 66 | $this->variablesMap = $variablesMap; 67 | } 68 | 69 | /** 70 | * @return string Feature ID. 71 | */ 72 | public function getId() 73 | { 74 | return $this->id; 75 | } 76 | 77 | /** 78 | * @return string Feature Key. 79 | */ 80 | public function getKey() 81 | { 82 | return $this->key; 83 | } 84 | 85 | /** 86 | * @return array array of feature Experiments as OptimizelyExperiments. 87 | */ 88 | public function getExperimentRules() 89 | { 90 | return $this->experimentRules; 91 | } 92 | 93 | /** 94 | * @return array array of Rollout Experiments of feature as OptimizelyExperiments. 95 | */ 96 | public function getDeliveryRules() 97 | { 98 | return $this->deliveryRules; 99 | } 100 | 101 | /** 102 | * @return array Map of Experiment Keys to OptimizelyExperiments. 103 | */ 104 | public function getExperimentsMap() 105 | { 106 | # This experimentsMap is deprecated. Use experimentRules and deliveryRules instead. 107 | return $this->experimentsMap; 108 | } 109 | 110 | /** 111 | * @return array Map of Variable Keys to OptimizelyVariables. 112 | */ 113 | public function getVariablesMap() 114 | { 115 | return $this->variablesMap; 116 | } 117 | 118 | /** 119 | * @return string JSON representation of the object. 120 | */ 121 | #[\ReturnTypeWillChange] 122 | public function jsonSerialize() 123 | { 124 | return get_object_vars($this); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Optimizely/OptimizelyConfig/OptimizelyVariable.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2020, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\OptimizelyConfig; 18 | 19 | class OptimizelyVariable implements \JsonSerializable 20 | { 21 | /** 22 | * @var string ID representing variable. 23 | */ 24 | private $id; 25 | 26 | /** 27 | * @var string Key representing variable. 28 | */ 29 | private $key; 30 | 31 | /** 32 | * @var String Variable denoting type of the variable. One of 33 | * boolean, integer, double or string. 34 | */ 35 | private $type; 36 | 37 | /** 38 | * @var string Value of the variable. 39 | */ 40 | private $value; 41 | 42 | public function __construct($id, $key, $type, $value) 43 | { 44 | $this->id = $id; 45 | $this->key = $key; 46 | $this->type = $type; 47 | $this->value = $value; 48 | } 49 | 50 | /** 51 | * @return string Variable ID. 52 | */ 53 | public function getId() 54 | { 55 | return $this->id; 56 | } 57 | 58 | /** 59 | * @return string Variable key. 60 | */ 61 | public function getKey() 62 | { 63 | return $this->key; 64 | } 65 | 66 | /** 67 | * @return string Variable type. 68 | */ 69 | public function getType() 70 | { 71 | return $this->type; 72 | } 73 | 74 | /** 75 | * @return string Variable value. 76 | */ 77 | public function getValue() 78 | { 79 | return $this->value; 80 | } 81 | 82 | /** 83 | * @return string JSON representation of the object. 84 | */ 85 | #[\ReturnTypeWillChange] 86 | public function jsonSerialize() 87 | { 88 | return get_object_vars($this); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Optimizely/OptimizelyConfig/OptimizelyVariation.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2020, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\OptimizelyConfig; 18 | 19 | class OptimizelyVariation implements \JsonSerializable 20 | { 21 | /** 22 | * @var string ID representing the variation. 23 | */ 24 | private $id; 25 | 26 | /** 27 | * @var string Key representing the variation. 28 | */ 29 | private $key; 30 | 31 | /** 32 | * @var boolean Flag representing if the feature is enabled. 33 | */ 34 | private $featureEnabled; 35 | 36 | /** 37 | * Map of Variable Keys to OptimizelyVariables. 38 | * 39 | * @var <String, OptimizelyVariable> associative array 40 | */ 41 | private $variablesMap; 42 | 43 | public function __construct($id, $key, $featureEnabled, array $variablesMap) 44 | { 45 | $this->id = $id; 46 | $this->key = $key; 47 | $this->featureEnabled = $featureEnabled; 48 | $this->variablesMap = $variablesMap; 49 | } 50 | 51 | /** 52 | * @return string Variation ID. 53 | */ 54 | public function getId() 55 | { 56 | return $this->id; 57 | } 58 | 59 | /** 60 | * @return string Variation key. 61 | */ 62 | public function getKey() 63 | { 64 | return $this->key; 65 | } 66 | 67 | /** 68 | * @return boolean featureEnabled property 69 | */ 70 | public function getFeatureEnabled() 71 | { 72 | return $this->featureEnabled; 73 | } 74 | 75 | /** 76 | * @return array Map of Variable Keys to OptimizelyVariables. 77 | */ 78 | public function getVariablesMap() 79 | { 80 | return $this->variablesMap; 81 | } 82 | 83 | /** 84 | * @return string JSON representation of the object. 85 | * Unsets featureEnabled property for variations of ab experiments. 86 | */ 87 | #[\ReturnTypeWillChange] 88 | public function jsonSerialize() 89 | { 90 | $props = get_object_vars($this); 91 | // featureEnabled prop is irrelevant for ab experiments. 92 | if ($this->featureEnabled === null) { 93 | unset($props['featureEnabled']); 94 | } 95 | 96 | return $props; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Optimizely/OptimizelyFactory.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2020, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely; 18 | 19 | use Optimizely\Optimizely; 20 | use Optimizely\ProjectConfigManager\HTTPProjectConfigManager; 21 | 22 | /** 23 | * Class OptimizelyFactory 24 | * 25 | * @package Optimizely 26 | */ 27 | class OptimizelyFactory 28 | { 29 | public static function createDefaultInstance( 30 | $sdkKey, 31 | $datafile = null, 32 | $datafileAccessToken = null 33 | ) { 34 | $configManager = new HTTPProjectConfigManager( 35 | $sdkKey, 36 | null, 37 | null, 38 | true, 39 | $datafile, 40 | false, 41 | null, 42 | null, 43 | null, 44 | $datafileAccessToken 45 | ); 46 | 47 | return new Optimizely( 48 | null, 49 | null, 50 | null, 51 | null, 52 | null, 53 | null, 54 | $configManager, 55 | null, 56 | null 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Optimizely/ProjectConfigManager/ProjectConfigManagerInterface.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2019, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\ProjectConfigManager; 19 | 20 | /** 21 | * Interface for Optimizely's config manager. 22 | */ 23 | interface ProjectConfigManagerInterface 24 | { 25 | /** 26 | * Returns ProjectConfig instance. 27 | */ 28 | public function getConfig(); 29 | } 30 | -------------------------------------------------------------------------------- /src/Optimizely/ProjectConfigManager/StaticProjectConfigManager.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2019, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\ProjectConfigManager; 19 | 20 | use Optimizely\Config\DatafileProjectConfig; 21 | use Optimizely\ErrorHandler\ErrorHandlerInterface; 22 | use Optimizely\Logger\LoggerInterface; 23 | 24 | /** 25 | * Project config manager that returns ProjectConfig based on provided datafile. 26 | */ 27 | class StaticProjectConfigManager implements ProjectConfigManagerInterface 28 | { 29 | /** 30 | * @var DatafileProjectConfig JSON datafile string. 31 | */ 32 | private $_config; 33 | 34 | /** 35 | * @var LoggerInterface JSON datafile string. 36 | */ 37 | private $_logger; 38 | 39 | /** 40 | * @var ErrorHandlerInterface JSON datafile string. 41 | */ 42 | private $_errorHandler; 43 | 44 | /** 45 | * Initialize config manager. Datafile has to be provided to use. 46 | * 47 | * @param string $datafile JSON string representing the Optimizely project. 48 | * @param bool $skipJsonValidation boolean representing whether JSON schema validation needs to be performed. 49 | * @param LoggerInterface $logger Logger instance 50 | * @param ErrorHandlerInterface $errorHandler ErrorHandler instance. 51 | */ 52 | public function __construct($datafile, $skipJsonValidation, $logger, $errorHandler) 53 | { 54 | $this->_logger = $logger; 55 | $this->_errorHandler = $errorHandler; 56 | $this->_config = DatafileProjectConfig::createProjectConfigFromDatafile($datafile, $skipJsonValidation, $logger, $errorHandler); 57 | } 58 | 59 | /** 60 | * Returns instance of ProjectConfig. 61 | * @return null|DatafileProjectConfig DatafileProjectConfig instance. 62 | */ 63 | public function getConfig() 64 | { 65 | return $this->_config; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Optimizely/UserProfile/Decision.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\UserProfile; 19 | 20 | class Decision 21 | { 22 | /** 23 | * @var string The ID variation in this decision. 24 | */ 25 | private $_variationId; 26 | 27 | /** 28 | * Decision constructor. 29 | * 30 | * @param $variationId 31 | */ 32 | public function __construct($variationId) 33 | { 34 | $this->_variationId = $variationId; 35 | } 36 | 37 | public function getVariationId() 38 | { 39 | return $this->_variationId; 40 | } 41 | 42 | public function setVariationId($variationId) 43 | { 44 | $this->_variationId = $variationId; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Optimizely/UserProfile/UserProfile.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\UserProfile; 19 | 20 | class UserProfile 21 | { 22 | /** 23 | * @var string The ID of the user. 24 | */ 25 | private $_userId; 26 | 27 | /** 28 | * @var array Bucketing decisions for the user. 29 | */ 30 | private $_experiment_bucket_map; 31 | 32 | /** 33 | * UserProfile constructor. 34 | * 35 | * @param $userId 36 | * @param $experimentBucketMap 37 | */ 38 | public function __construct($userId, $experiment_bucket_map = array()) 39 | { 40 | $this->_userId = $userId; 41 | $this->_experiment_bucket_map = $experiment_bucket_map; 42 | } 43 | 44 | /** 45 | * @return string ID of the user. 46 | */ 47 | public function getUserId() 48 | { 49 | return $this->_userId; 50 | } 51 | 52 | /** 53 | * @return array Experiment to decision map. 54 | */ 55 | public function getExperimentBucketMap() 56 | { 57 | return $this->_experiment_bucket_map; 58 | } 59 | 60 | /** 61 | * Get the variation ID for the given experiment from the experiment bucket map. 62 | * 63 | * @param $experimentId string The ID of the experiment. 64 | * 65 | * @return null|string The variation ID. 66 | */ 67 | public function getVariationForExperiment($experimentId) 68 | { 69 | $decision = $this->getDecisionForExperiment($experimentId); 70 | if (!is_null($decision)) { 71 | return $decision->getVariationId(); 72 | } 73 | 74 | return null; 75 | } 76 | 77 | /** 78 | * Get the decision for the given experiment from the experiment bucket map. 79 | * 80 | * @param $experimentId string The ID of the experiment. 81 | * 82 | * @return null|Decision The decision for the given experiment. 83 | */ 84 | public function getDecisionForExperiment($experimentId) 85 | { 86 | if (isset($this->_experiment_bucket_map[$experimentId])) { 87 | return $this->_experiment_bucket_map[$experimentId]; 88 | } 89 | 90 | return null; 91 | } 92 | 93 | /** 94 | * Set the decision for the given experiment. 95 | * 96 | * @param $experimentId string The ID of the experiment. 97 | * @param $decision Decision The decision for the experiment. 98 | */ 99 | public function saveDecisionForExperiment($experimentId, Decision $decision) 100 | { 101 | $this->_experiment_bucket_map[$experimentId] = $decision; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Optimizely/UserProfile/UserProfileServiceInterface.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, 2023, Optimizely Inc, and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\UserProfile; 18 | 19 | interface UserProfileServiceInterface 20 | { 21 | /** 22 | * Fetch the user profile map for the user ID. 23 | * 24 | * @param $userId string The ID of the user whose profile will be retrieved. 25 | * 26 | * @return array The user profile. 27 | */ 28 | public function lookup($userId); 29 | 30 | /** 31 | * Save the user profile Map sent to this method. 32 | * 33 | * @param $userProfile array The user profile to save. 34 | */ 35 | public function save($userProfile); 36 | } 37 | -------------------------------------------------------------------------------- /src/Optimizely/UserProfile/UserProfileUtils.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\UserProfile; 19 | 20 | class UserProfileUtils 21 | { 22 | const USER_ID_KEY = 'user_id'; 23 | 24 | const EXPERIMENT_BUCKET_MAP_KEY = 'experiment_bucket_map'; 25 | 26 | const VARIATION_ID_KEY = 'variation_id'; 27 | 28 | /** 29 | * Grab the revenue value from the event tags. "revenue" is a reserved keyword. 30 | * 31 | * @param $userProfileMap array Representing the user profile. 32 | * @return true if the given user profile map is valid, false otherwise. 33 | */ 34 | public static function isValidUserProfileMap($userProfileMap) 35 | { 36 | if (!is_array($userProfileMap)) { 37 | return false; 38 | } 39 | 40 | if (!isset($userProfileMap[self::USER_ID_KEY])) { 41 | return false; 42 | } 43 | 44 | if (!isset($userProfileMap[self::EXPERIMENT_BUCKET_MAP_KEY])) { 45 | return false; 46 | } 47 | 48 | if (!is_array($userProfileMap[self::EXPERIMENT_BUCKET_MAP_KEY])) { 49 | return false; 50 | } 51 | 52 | // validate the experiment bucket map 53 | $experimentBucketMap = $userProfileMap[self::EXPERIMENT_BUCKET_MAP_KEY]; 54 | foreach ($experimentBucketMap as $experimentId => $decision) { 55 | if (!is_array($decision)) { 56 | return false; 57 | } 58 | 59 | // make sure that there is a variation ID property in every decision 60 | if (!isset($decision[self::VARIATION_ID_KEY])) { 61 | return false; 62 | } 63 | } 64 | 65 | // Looks good to me 66 | return true; 67 | } 68 | 69 | /** 70 | * Convert the given user profile map into a UserProfile object. 71 | * 72 | * @param $userProfileMap array 73 | * 74 | * @return UserProfile The user profile object constructed from the given map. 75 | */ 76 | public static function convertMapToUserProfile($userProfileMap) 77 | { 78 | $userId = $userProfileMap[self::USER_ID_KEY]; 79 | $experimentBucketMap = array(); 80 | foreach ($userProfileMap[self::EXPERIMENT_BUCKET_MAP_KEY] as $experimentId => $decisionMap) { 81 | $variationId = $decisionMap[self::VARIATION_ID_KEY]; 82 | $experimentBucketMap[$experimentId] = new Decision($variationId); 83 | } 84 | 85 | return new UserProfile($userId, $experimentBucketMap); 86 | } 87 | 88 | /** 89 | * Convert the given UserProfile object into a map. 90 | * 91 | * @param $userProfile UserProfile The user profile object to convert to a map. 92 | * 93 | * @return array The map representing the user profile object. 94 | */ 95 | public static function convertUserProfileToMap($userProfile) 96 | { 97 | $userProfileMap = array( 98 | self::USER_ID_KEY => $userProfile->getUserId(), 99 | self::EXPERIMENT_BUCKET_MAP_KEY => array() 100 | ); 101 | $experimentBucketMap = $userProfile->getExperimentBucketMap(); 102 | foreach ($experimentBucketMap as $experimentId => $decision) { 103 | $userProfileMap[self::EXPERIMENT_BUCKET_MAP_KEY][$experimentId] = array( 104 | self::VARIATION_ID_KEY => $decision->getVariationId() 105 | ); 106 | } 107 | return $userProfileMap; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/Optimizely/Utils/ConditionTreeEvaluator.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2018-2019, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Utils; 19 | 20 | class ConditionTreeEvaluator 21 | { 22 | const AND_OPERATOR = 'and'; 23 | const OR_OPERATOR = 'or'; 24 | const NOT_OPERATOR = 'not'; 25 | 26 | /** 27 | * Returns an array of supported operators. 28 | * 29 | * @return array List of operators. 30 | */ 31 | protected function getOperators() 32 | { 33 | return array(self::AND_OPERATOR, self::OR_OPERATOR, self::NOT_OPERATOR); 34 | } 35 | 36 | /** 37 | * Returns corresponding evaluator method name for the given operator. 38 | * 39 | * @param mixed $operator Operator to get relevant evaluator method. 40 | * 41 | * @return string Corresponding method to the given operator. 42 | */ 43 | protected function getEvaluatorByOperatorType($operator) 44 | { 45 | $evaluatorsByOperator = array(); 46 | $evaluatorsByOperator[self::AND_OPERATOR] = 'andEvaluator'; 47 | $evaluatorsByOperator[self::OR_OPERATOR] = 'orEvaluator'; 48 | $evaluatorsByOperator[self::NOT_OPERATOR] = 'notEvaluator'; 49 | 50 | return $evaluatorsByOperator[$operator]; 51 | } 52 | 53 | /** 54 | * Evaluates an array of conditions as if the evaluator had been applied 55 | * to each entry and the results AND-ed together. 56 | * 57 | * @param array $conditions Audience conditions list. 58 | * @param callable $leafEvaluator Method to evaluate leaf condition. 59 | * 60 | * @return null|boolean True if all the operands evaluate to true. 61 | * False if a single operand evaluates to false. 62 | * Null if conditions couldn't be evaluated. 63 | */ 64 | protected function andEvaluator(array $conditions, callable $leafEvaluator) 65 | { 66 | $sawNullResult = false; 67 | foreach ($conditions as $condition) { 68 | $result = $this->evaluate($condition, $leafEvaluator); 69 | 70 | if ($result === false) { 71 | return false; 72 | } 73 | 74 | if ($result === null) { 75 | $sawNullResult = true; 76 | } 77 | } 78 | 79 | return $sawNullResult ? null : true; 80 | } 81 | 82 | /** 83 | * Evaluates an array of conditions as if the evaluator had been applied 84 | * to each entry and the results OR-ed together. 85 | * 86 | * @param array $conditions Audience conditions list. 87 | * @param callable $leafEvaluator Method to evaluate leaf condition. 88 | * 89 | * @return null|boolean True if any operand evaluates to true. 90 | * False if all operands evaluate to false. 91 | * Null if conditions couldn't be evaluated. 92 | */ 93 | protected function orEvaluator(array $conditions, callable $leafEvaluator) 94 | { 95 | $sawNullResult = false; 96 | foreach ($conditions as $condition) { 97 | $result = $this->evaluate($condition, $leafEvaluator); 98 | 99 | if ($result === true) { 100 | return true; 101 | } 102 | 103 | if ($result === null) { 104 | $sawNullResult = true; 105 | } 106 | } 107 | 108 | return $sawNullResult ? null : false; 109 | } 110 | 111 | /** 112 | * Evaluates an array of conditions as if the evaluator had been applied 113 | * to a single entry and NOT was applied to the result. 114 | * 115 | * @param array $conditions Audience conditions list. 116 | * @param callable $leafEvaluator Method to evaluate leaf condition. 117 | * 118 | * @return null|boolean True if the operand evaluates to false. 119 | * False if the operand evaluates to true. 120 | * Null if conditions is empty or couldn't be evaluated. 121 | */ 122 | protected function notEvaluator(array $condition, callable $leafEvaluator) 123 | { 124 | if (empty($condition)) { 125 | return null; 126 | } 127 | 128 | $result = $this->evaluate($condition[0], $leafEvaluator); 129 | return $result === null ? null: !$result; 130 | } 131 | 132 | /** 133 | * Function to evaluate audience conditions against user's attributes. 134 | * 135 | * @param array $conditions Nested array of and/or/not conditions representing the audience conditions. 136 | * @param callable $leafEvaluator Method to evaluate leaf condition. 137 | * 138 | * @return null|boolean Result of evaluating the conditions using the operator rules. 139 | * and the leaf evaluator. Null if conditions couldn't be evaluated. 140 | */ 141 | public function evaluate($conditions, callable $leafEvaluator) 142 | { 143 | // When parsing audiences tree the leaf node is a string representing an audience ID. 144 | // When parsing conditions of a single audience the leaf node is an associative array with all keys of type string. 145 | if (is_string($conditions) || Validator::doesArrayContainOnlyStringKeys($conditions)) { 146 | $leafCondition = $conditions; 147 | return $leafEvaluator($leafCondition); 148 | } 149 | 150 | if (in_array($conditions[0], $this->getOperators())) { 151 | $operator = array_shift($conditions); 152 | } else { 153 | $operator = self::OR_OPERATOR; 154 | } 155 | 156 | $evaluatorFunc = $this->getEvaluatorByOperatorType($operator); 157 | return $this->{$evaluatorFunc}($conditions, $leafEvaluator); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/Optimizely/Utils/ConfigParser.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016-2017, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Utils; 18 | 19 | class ConfigParser 20 | { 21 | 22 | /** 23 | * @param $entities array Entities to be stored as objects. 24 | * @param $entityId string ID to be used in generating map. 25 | * @param $entityClass string Class of entities. 26 | * 27 | * @return array Map mapping entity identifier to the entity. 28 | */ 29 | public static function generateMap($entities, $entityId, $entityClass) 30 | { 31 | $entityMap = []; 32 | foreach ($entities as $entity) { 33 | if ($entity instanceof $entityClass) { 34 | $entityObject = $entity; 35 | } else { 36 | $entityObject = new $entityClass; 37 | foreach ($entity as $key => $value) { 38 | $propSetter = 'set'.ucfirst($key); 39 | if (method_exists($entityObject, $propSetter)) { 40 | $entityObject->$propSetter($value); 41 | } 42 | } 43 | } 44 | 45 | if (is_null($entityId)) { 46 | array_push($entityMap, $entityObject); 47 | } else { 48 | $propKeyGetter = 'get'.ucfirst($entityId); 49 | $entityMap[$entityObject->$propKeyGetter()] = $entityObject; 50 | } 51 | } 52 | 53 | return $entityMap; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Optimizely/Utils/Errors.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2018, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Utils; 18 | 19 | class Errors 20 | { 21 | const INVALID_FORMAT = 'Provided %s is in an invalid format.'; 22 | const INVALID_DATAFILE = 'Datafile has invalid format. Failing "%s".'; 23 | const NO_CONFIG = 'Optimizely SDK not configured properly yet.'; 24 | } 25 | -------------------------------------------------------------------------------- /src/Optimizely/Utils/EventTagUtils.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017-2019, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Utils; 19 | 20 | use Optimizely\Logger\LoggerInterface; 21 | use Optimizely\Logger\NoOpLogger; 22 | use Monolog\Logger; 23 | 24 | class EventTagUtils 25 | { 26 | /** 27 | * @const string Reserved word for event tag representing event revenue value. 28 | */ 29 | const REVENUE_EVENT_METRIC_NAME = 'revenue'; 30 | 31 | const NUMERIC_EVENT_METRIC_NAME = 'value'; 32 | 33 | /** 34 | * Grab the revenue value from the event tags. "revenue" is a reserved keyword. 35 | * The value will be parsed to an integer if possible. 36 | * Example: 37 | * 4.0 or "4.0" will be parsed to int(4). 38 | * 4.1 will not be parsed and the method will return null. 39 | * 40 | * @param $eventTags array Representing metadata associated with the event. 41 | * @return integer Revenue value as an integer number or null if revenue can't be retrieved from the event tags 42 | */ 43 | public static function getRevenueValue($eventTags, $logger) 44 | { 45 | if (!$eventTags) { 46 | $logger->log(Logger::DEBUG, "Event tags is undefined."); 47 | return null; 48 | } 49 | if (!is_array($eventTags)) { 50 | $logger->log(Logger::DEBUG, "Event tags is not a dictionary."); 51 | return null; 52 | } 53 | 54 | if (!isset($eventTags[self::REVENUE_EVENT_METRIC_NAME])) { 55 | $logger->log(Logger::DEBUG, "The revenue key is not defined in the event tags or is null."); 56 | return null; 57 | } 58 | 59 | $rawValue = $eventTags[self::REVENUE_EVENT_METRIC_NAME]; 60 | 61 | if (!is_numeric($rawValue)) { 62 | $logger->log(Logger::DEBUG, "Revenue value is not an integer or float, or is not a numeric string."); 63 | return null; 64 | } 65 | 66 | if ($rawValue != intval($rawValue)) { 67 | $logger->log(Logger::DEBUG, "Revenue value couldn't be parsed as an integer."); 68 | return null; 69 | } 70 | 71 | $rawValue = intval($rawValue); 72 | $logger->log(Logger::INFO, "The revenue value {$rawValue} will be sent to results."); 73 | return $rawValue; 74 | } 75 | 76 | /** 77 | * Grab the numeric event value from the event tags. "value" is a reserved keyword. 78 | * The value of 'value' can be a float or a numeric string 79 | * 80 | * @param $eventTags array Representing metadata associated with the event. 81 | * @param $logger instance of LoggerInterface 82 | * 83 | * @return float value of 'value' or null 84 | */ 85 | public static function getNumericValue($eventTags, $logger) 86 | { 87 | if (!$eventTags) { 88 | $logger->log(Logger::DEBUG, "Event tags is undefined."); 89 | return null; 90 | } 91 | 92 | if (!is_array($eventTags)) { 93 | $logger->log(Logger::DEBUG, "Event tags is not a dictionary."); 94 | return null; 95 | } 96 | 97 | if (!isset($eventTags[self::NUMERIC_EVENT_METRIC_NAME])) { 98 | $logger->log(Logger::DEBUG, "The numeric metric key is not defined in the event tags or is null."); 99 | return null; 100 | } 101 | 102 | if (!is_numeric($eventTags[self::NUMERIC_EVENT_METRIC_NAME])) { 103 | $logger->log(Logger::DEBUG, "Numeric metric value is not an integer or float, or is not a numeric string."); 104 | return null; 105 | } 106 | 107 | if (is_nan($eventTags[self::NUMERIC_EVENT_METRIC_NAME]) || is_infinite(floatval($eventTags[self::NUMERIC_EVENT_METRIC_NAME]))) { 108 | $logger->log(Logger::DEBUG, "Provided numeric value is in an invalid format."); 109 | return null; 110 | } 111 | 112 | $rawValue = $eventTags[self::NUMERIC_EVENT_METRIC_NAME]; 113 | // # Log the final numeric metric value 114 | $logger->log(Logger::INFO, "The numeric metric value {$rawValue} will be sent to results."); 115 | 116 | return floatval($rawValue); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/Optimizely/Utils/GeneratorUtils.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Utils; 19 | 20 | class GeneratorUtils 21 | { 22 | /** 23 | * Generate random uuid 24 | * 25 | * @return string - version 4 uuid 26 | */ 27 | public static function getRandomUuid() 28 | { 29 | return sprintf( 30 | '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', 31 | // 32 bits for "time_low" 32 | mt_rand(0, 0xffff), 33 | mt_rand(0, 0xffff), 34 | // 16 bits for "time_mid" 35 | mt_rand(0, 0xffff), 36 | // 16 bits for "time_hi_and_version", 37 | // four most significant bits holds version number 4 38 | mt_rand(0, 0x0fff) | 0x4000, 39 | // 16 bits, 8 bits for "clk_seq_hi_res", 40 | // 8 bits for "clk_seq_low", 41 | // two most significant bits holds zero and one for variant DCE1.1 42 | mt_rand(0, 0x3fff) | 0x8000, 43 | // 48 bits for "node" 44 | mt_rand(0, 0xffff), 45 | mt_rand(0, 0xffff), 46 | mt_rand(0, 0xffff) 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Optimizely/Utils/VariableTypeUtils.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, 2019-2020 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Utils; 19 | 20 | use Exception; 21 | use Monolog\Logger; 22 | use Optimizely\Entity\FeatureVariable; 23 | use Optimizely\Logger\LoggerInterface; 24 | 25 | class VariableTypeUtils 26 | { 27 | public static function castStringToType($value, $variableType, LoggerInterface $logger = null) 28 | { 29 | if ($variableType == FeatureVariable::STRING_TYPE) { 30 | return $value; 31 | } 32 | 33 | $return_value = null; 34 | 35 | switch ($variableType) { 36 | case FeatureVariable::BOOLEAN_TYPE: 37 | $return_value = strtolower($value) == "true"; 38 | break; 39 | 40 | case FeatureVariable::INTEGER_TYPE: 41 | if (ctype_digit($value)) { 42 | $return_value = (int) $value; 43 | } 44 | break; 45 | 46 | case FeatureVariable::DOUBLE_TYPE: 47 | if (is_numeric($value)) { 48 | $return_value = (float) $value; 49 | } 50 | break; 51 | 52 | case FeatureVariable::JSON_TYPE: 53 | $return_value = json_decode($value, true); 54 | break; 55 | } 56 | 57 | if (is_null($return_value) && $logger) { 58 | $logger->log(Logger::ERROR, "Unable to cast variable value '{$value}' to type '{$variableType}'."); 59 | } 60 | 61 | return $return_value; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/ErrorHandlerTests/DefaultErrorHandlerTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, 2023 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Tests; 18 | 19 | use Exception; 20 | use Optimizely\ErrorHandler\DefaultErrorHandler; 21 | use PHPUnit\Framework\TestCase; 22 | 23 | class DefaultErrorHandlerTest extends TestCase 24 | { 25 | public function testHandleError() 26 | { 27 | $this->expectExceptionMessage("Throw me please."); 28 | $this->expectException(Exception::class); 29 | $exception = new Exception('Throw me please.'); 30 | $errorHandler = new DefaultErrorHandler(); 31 | 32 | $errorHandler->handleError($exception); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/ErrorHandlerTests/NoOpErrorHandlerTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, 2023 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Tests; 19 | 20 | use Exception; 21 | use Optimizely\ErrorHandler\NoOpErrorHandler; 22 | use PHPUnit\Framework\TestCase; 23 | 24 | class NoOpErrorHandlerTest extends TestCase 25 | { 26 | public function testHandleError() 27 | { 28 | $exception = new Exception('I should do nothing.'); 29 | $errorHandler = new NoOpErrorHandler(); 30 | 31 | $errorHandler->handleError($exception); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/EventTests/DefaultEventDispatcherTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, 2023 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Tests; 18 | 19 | use GuzzleHttp\Client as HttpClient; 20 | use Optimizely\Event\Dispatcher\DefaultEventDispatcher; 21 | use Optimizely\Event\LogEvent; 22 | use PHPUnit\Framework\TestCase; 23 | 24 | class DefaultEventDispatcherTest extends TestCase 25 | { 26 | public function testDispatchEvent() 27 | { 28 | $logEvent = new LogEvent( 29 | 'https://logx.optimizely.com', 30 | [ 31 | 'accountId' => '1234', 32 | 'projectId' => '9876', 33 | 'visitorId' => 'testUser' 34 | ], 35 | 'POST', 36 | [ 37 | 'Content-Type' => 'application/json' 38 | ] 39 | ); 40 | 41 | $expectedOptions = [ 42 | 'headers' => $logEvent->getHeaders(), 43 | 'json' => $logEvent->getParams(), 44 | 'timeout' => 10, 45 | 'connect_timeout' => 10 46 | ]; 47 | 48 | $guzzleClientMock = $this->getMockBuilder(HttpClient::class) 49 | ->getMock(); 50 | 51 | $guzzleClientMock->expects($this->once()) 52 | ->method('request') 53 | ->with($logEvent->getHttpVerb(), $logEvent->getUrl(), $expectedOptions); 54 | 55 | $eventDispatcher = new DefaultEventDispatcher($guzzleClientMock); 56 | $eventDispatcher->dispatchEvent($logEvent); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tests/EventTests/LogEventTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, 2023 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Tests; 19 | 20 | use Optimizely\Event\LogEvent; 21 | use PHPUnit\Framework\TestCase; 22 | 23 | class LogEventTest extends TestCase 24 | { 25 | private $logEvent; 26 | 27 | protected function setUp() : void 28 | { 29 | $this->logEvent = new LogEvent( 30 | 'https://logx.optimizely.com', 31 | [ 32 | 'accountId' => '1234', 33 | 'projectId' => '9876', 34 | 'visitorId' => 'testUser' 35 | ], 36 | 'POST', 37 | [ 38 | 'Content-Type' => 'application/json' 39 | ] 40 | ); 41 | } 42 | 43 | public function testGetUrl() 44 | { 45 | $this->assertEquals('https://logx.optimizely.com', $this->logEvent->getUrl()); 46 | } 47 | 48 | public function testGetParams() 49 | { 50 | $this->assertEquals( 51 | [ 52 | 'accountId' => '1234', 53 | 'projectId' => '9876', 54 | 'visitorId' => 'testUser' 55 | ], 56 | $this->logEvent->getParams() 57 | ); 58 | } 59 | 60 | public function testGetHttpVerb() 61 | { 62 | $this->assertEquals('POST', $this->logEvent->getHttpVerb()); 63 | } 64 | 65 | public function testGetHeaders() 66 | { 67 | $this->assertEquals(['Content-Type' => 'application/json'], $this->logEvent->getHeaders()); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/LoggerTests/DefaultLoggerTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, 2018, 2023 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Tests; 18 | 19 | use Monolog\Logger; 20 | use Optimizely\Logger\DefaultLogger; 21 | use PHPUnit\Framework\TestCase; 22 | 23 | class DefaultLoggerTest extends TestCase 24 | { 25 | public function testDefaultLogger() 26 | { 27 | $logger = new DefaultLogger(Logger::INFO, 'output'); 28 | $logger->log(Logger::INFO, 'Log me please.'); 29 | 30 | $this->expectOutputRegex('/Log me please./'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/LoggerTests/NoOpLoggerTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2016, 2023 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Tests; 18 | 19 | use Monolog\Logger; 20 | use Optimizely\Logger\NoOpLogger; 21 | use PHPUnit\Framework\TestCase; 22 | 23 | class NoOpLoggerTest extends TestCase 24 | { 25 | public function testNoOpLogger() 26 | { 27 | $logger= new NoOpLogger(); 28 | $logger->log(Logger::INFO, 'I wont be logged.'); 29 | 30 | $this->expectOutputString(''); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/OptimizelyFactoryTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2020, 2023 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | namespace Optimizely\Tests; 18 | 19 | use Exception; 20 | use GuzzleHttp\Client; 21 | use GuzzleHttp\Handler\MockHandler; 22 | use GuzzleHttp\HandlerStack; 23 | use GuzzleHttp\Middleware; 24 | use GuzzleHttp\Psr7\Response; 25 | use Optimizely\OptimizelyFactory; 26 | use Optimizely\ProjectConfigManager\HTTPProjectConfigManager; 27 | use PHPUnit\Framework\TestCase; 28 | 29 | class OptimizelyFactoryTest extends TestCase 30 | { 31 | protected function setUp() : void 32 | { 33 | $this->datafile = DATAFILE; 34 | $this->typedAudiencesDataFile = DATAFILE_WITH_TYPED_AUDIENCES; 35 | } 36 | 37 | public function testDefaultInstance() 38 | { 39 | $optimizelyClient = OptimizelyFactory::createDefaultInstance("some-sdk-key", $this->datafile); 40 | 41 | // client hasn't been mocked yet. Hence, config manager should return config of hardcoded 42 | // datafile. 43 | $this->assertEquals('15', $optimizelyClient->configManager->getConfig()->getRevision()); 44 | 45 | // Mock http client to return a valid datafile 46 | $mock = new MockHandler([ 47 | new Response(200, [], $this->typedAudiencesDataFile) 48 | ]); 49 | 50 | $handler = HandlerStack::create($mock); 51 | 52 | $client = new Client(['handler' => $handler]); 53 | $httpClient = new \ReflectionProperty(HTTPProjectConfigManager::class, 'httpClient'); 54 | $httpClient->setAccessible(true); 55 | $httpClient->setValue($optimizelyClient->configManager, $client); 56 | 57 | /// Fetch datafile 58 | $optimizelyClient->configManager->fetch(); 59 | 60 | $this->assertEquals('3', $optimizelyClient->configManager->getConfig()->getRevision()); 61 | } 62 | 63 | public function testDefaultInstanceWithAccessToken() 64 | { 65 | $optimizelyClient = OptimizelyFactory::createDefaultInstance( 66 | "some-sdk-key", 67 | null, 68 | "some_token" 69 | ); 70 | 71 | // Mock http client to return a valid datafile 72 | $mock = new MockHandler([ 73 | new Response(200, [], $this->typedAudiencesDataFile) 74 | ]); 75 | 76 | $container = []; 77 | $history = Middleware::history($container); 78 | $handler = HandlerStack::create($mock); 79 | $handler->push($history); 80 | 81 | $client = new Client(['handler' => $handler]); 82 | $httpClient = new \ReflectionProperty(HTTPProjectConfigManager::class, 'httpClient'); 83 | $httpClient->setAccessible(true); 84 | $httpClient->setValue($optimizelyClient->configManager, $client); 85 | 86 | /// Fetch datafile 87 | $optimizelyClient->configManager->fetch(); 88 | 89 | $this->assertEquals('3', $optimizelyClient->configManager->getConfig()->getRevision()); 90 | 91 | // assert that https call is made to mock as expected. 92 | $transaction = $container[0]; 93 | $this->assertEquals( 94 | 'https://config.optimizely.com/datafiles/auth/some-sdk-key.json', 95 | $transaction['request']->getUri() 96 | ); 97 | 98 | // assert that headers include authorization access token 99 | $this->assertEquals( 100 | 'Bearer some_token', 101 | $transaction['request']->getHeaders()['Authorization'][0] 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /tests/ProjectConfigManagerTests/StaticProjectConfigManagerTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2019, 2023 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Tests; 19 | 20 | use Monolog\Logger; 21 | use Optimizely\Config\DatafileProjectConfig; 22 | use Optimizely\ErrorHandler\NoOpErrorHandler; 23 | use Optimizely\Exceptions\InvalidDatafileVersionException; 24 | use Optimizely\Logger\NoOpLogger; 25 | use Optimizely\ProjectConfigManager\StaticProjectConfigManager; 26 | use PHPUnit\Framework\TestCase; 27 | 28 | class StaticProjectConfigManagerTest extends TestCase 29 | { 30 | private $loggerMock; 31 | private $errorHandlerMock; 32 | 33 | protected function setUp() : void 34 | { 35 | // Mock Logger 36 | $this->loggerMock = $this->getMockBuilder(NoOpLogger::class) 37 | ->setMethods(array('log')) 38 | ->getMock(); 39 | 40 | $this->errorHandlerMock = $this->getMockBuilder(NoOpErrorHandler::class) 41 | ->setMethods(array('handleError')) 42 | ->getMock(); 43 | } 44 | 45 | public function testStaticProjectConfigManagerWithInvalidDatafile() 46 | { 47 | $this->loggerMock->expects($this->once()) 48 | ->method('log') 49 | ->with(Logger::ERROR, 'Provided "datafile" has invalid schema.'); 50 | 51 | $configManager = new StaticProjectConfigManager('Invalid datafile', false, $this->loggerMock, $this->errorHandlerMock); 52 | $this->assertNull($configManager->getConfig()); 53 | } 54 | 55 | public function testStaticProjectConfigManagerWithUnsupportedVersionDatafile() 56 | { 57 | $this->loggerMock->expects($this->once()) 58 | ->method('log') 59 | ->with(Logger::ERROR, 'This version of the PHP SDK does not support the given datafile version: 5.'); 60 | 61 | $this->errorHandlerMock->expects($this->once()) 62 | ->method('handleError') 63 | ->with(new InvalidDatafileVersionException('This version of the PHP SDK does not support the given datafile version: 5.')); 64 | 65 | $configManager = new StaticProjectConfigManager(UNSUPPORTED_DATAFILE, false, $this->loggerMock, $this->errorHandlerMock); 66 | $this->assertNull($configManager->getConfig()); 67 | } 68 | 69 | public function testStaticProjectConfigManagerWithValidDatafile() 70 | { 71 | $config = new DatafileProjectConfig(DATAFILE, $this->loggerMock, $this->errorHandlerMock); 72 | $configManager = new StaticProjectConfigManager(DATAFILE, false, $this->loggerMock, $this->errorHandlerMock); 73 | $this->assertEquals($config, $configManager->getConfig()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/UserProfileTests/UserProfileTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, 2023 Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Tests; 19 | 20 | use Optimizely\UserProfile\Decision; 21 | use Optimizely\UserProfile\UserProfile; 22 | use PHPUnit\Framework\TestCase; 23 | 24 | class UserProfileTest extends TestCase 25 | { 26 | private $userProfile; 27 | 28 | protected function setUp() : void 29 | { 30 | $experimentBucketMap = array(); 31 | $experimentBucketMap['111111'] = new Decision('211111'); 32 | $this->userProfile = new UserProfile( 33 | 'user_1', 34 | $experimentBucketMap 35 | ); 36 | } 37 | 38 | public function testGetVariationForExperiment() 39 | { 40 | $this->assertEquals('211111', $this->userProfile->getVariationForExperiment('111111')); 41 | } 42 | 43 | public function testGetDecisionForExperiment() 44 | { 45 | $expectedDecision = new Decision('211111'); 46 | $this->assertEquals($expectedDecision, $this->userProfile->getDecisionForExperiment('111111')); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/UserProfileTests/UserProfileUtilsTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, 2023 Optimizely Inc and Contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Tests; 19 | 20 | use Optimizely\Entity\Experiment; 21 | use Optimizely\UserProfile\Decision; 22 | use Optimizely\UserProfile\UserProfile; 23 | use Optimizely\UserProfile\UserProfileUtils; 24 | use PHPUnit\Framework\TestCase; 25 | 26 | class UserProfileUtilsTest extends TestCase 27 | { 28 | private $userProfileMap; 29 | 30 | protected function setUp() : void 31 | { 32 | $this->userProfileMap = array( 33 | 'user_id' => 'test_user', 34 | 'experiment_bucket_map' => array( 35 | '111111' => array( 36 | 'variation_id' => '211111' 37 | ), 38 | '111112' => array( 39 | 'variation_id' => '211113' 40 | ) 41 | ) 42 | ); 43 | } 44 | 45 | public function testIsValidUserProfileMap() 46 | { 47 | $profileNotArray = 'string'; 48 | $this->assertFalse(UserProfileUtils::isValidUserProfileMap($profileNotArray)); 49 | 50 | $profileWithMissingId = array( 51 | 'experiment_bucket_map' => array() 52 | ); 53 | $this->assertFalse(UserProfileUtils::isValidUserProfileMap($profileWithMissingId)); 54 | 55 | $profileWithMissingExperimentBucketMap = array( 56 | 'user_id' => null, 57 | ); 58 | $this->assertFalse(UserProfileUtils::isValidUserProfileMap($profileWithMissingExperimentBucketMap)); 59 | 60 | $profileWithBadExperimentBucketMap = array( 61 | 'user_id' => null, 62 | 'experiment_bucket_map' => array( 63 | '111111' => array( 64 | 'not_expected_key' => '211111' 65 | ) 66 | ) 67 | ); 68 | $this->assertFalse(UserProfileUtils::isValidUserProfileMap($profileWithBadExperimentBucketMap)); 69 | 70 | $validUserProfileMap = $this->userProfileMap; 71 | $this->assertTrue(UserProfileUtils::isValidUserProfileMap($validUserProfileMap)); 72 | } 73 | 74 | public function testConvertMapToUserProfile() 75 | { 76 | $expectedUserProfile = new UserProfile( 77 | 'test_user', 78 | array( 79 | '111111' => new Decision('211111'), 80 | '111112' => new Decision('211113') 81 | ) 82 | ); 83 | 84 | $this->assertEquals($expectedUserProfile, UserProfileUtils::convertMapToUserProfile($this->userProfileMap)); 85 | } 86 | 87 | public function testConvertUserProfileToMap() 88 | { 89 | $userProfileObject = new UserProfile( 90 | 'test_user', 91 | array( 92 | '111111' => new Decision('211111'), 93 | '111112' => new Decision('211113') 94 | ) 95 | ); 96 | 97 | $expectedUserProfileMap = array( 98 | 'user_id' => 'test_user', 99 | 'experiment_bucket_map' => array( 100 | '111111' => array('variation_id' => '211111'), 101 | '111112' => array('variation_id' => '211113') 102 | ) 103 | ); 104 | 105 | $this->assertEquals($expectedUserProfileMap, UserProfileUtils::convertUserProfileToMap($userProfileObject)); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /tests/UtilsTests/ValidatorLoggingTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2019-2021, 2023 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Tests; 19 | 20 | use Monolog\Logger; 21 | use Optimizely\Config\DatafileProjectConfig; 22 | use Optimizely\ErrorHandler\NoOpErrorHandler; 23 | use Optimizely\Logger\NoOpLogger; 24 | use Optimizely\Utils\Validator; 25 | use PHPUnit\Framework\TestCase; 26 | 27 | class ValidatorLoggingTest extends TestCase 28 | { 29 | protected function setUp() : void 30 | { 31 | $this->loggerMock = $this->getMockBuilder(NoOpLogger::class) 32 | ->setMethods(array('log')) 33 | ->getMock(); 34 | 35 | $this->config = new DatafileProjectConfig(DATAFILE, new NoOpLogger(), new NoOpErrorHandler()); 36 | 37 | $this->typedConfig = new DatafileProjectConfig(DATAFILE_WITH_TYPED_AUDIENCES, new NoOpLogger(), new NoOpErrorHandler()); 38 | 39 | $this->collectedLogs = []; 40 | 41 | $this->collectLogsForAssertion = function ($a, $b) { 42 | $this->collectedLogs[] = array($a,$b); 43 | }; 44 | } 45 | 46 | public function testdoesUserMeetAudienceConditionsWithNoAudience() 47 | { 48 | $experiment = $this->config->getExperimentFromKey('test_experiment'); 49 | $experiment->setAudienceIds([]); 50 | $experiment->setAudienceConditions([]); 51 | 52 | $this->loggerMock->expects($this->at(0)) 53 | ->method('log') 54 | ->with(Logger::DEBUG, "Evaluating audiences for experiment \"test_experiment\": []."); 55 | 56 | $evalCombinedAudienceMessage = "Audiences for experiment \"test_experiment\" collectively evaluated to TRUE."; 57 | $this->loggerMock->expects($this->at(1)) 58 | ->method('log') 59 | ->with(Logger::INFO, $evalCombinedAudienceMessage); 60 | 61 | list($evalResult, $reasons) = Validator::doesUserMeetAudienceConditions($this->config, $experiment, [], $this->loggerMock); 62 | $this->assertTrue($evalResult); 63 | $this->assertContains($evalCombinedAudienceMessage, $reasons); 64 | $this->assertCount(1, $reasons); 65 | } 66 | 67 | public function testdoesUserMeetAudienceConditionsEvaluatesAudienceIds() 68 | { 69 | $userAttributes = [ 70 | "test_attribute" => "test_value_1" 71 | ]; 72 | 73 | $experiment = $this->config->getExperimentFromKey('test_experiment'); 74 | $experiment->setAudienceIds(['11155']); 75 | $experiment->setAudienceConditions(null); 76 | 77 | $this->loggerMock->expects($this->any()) 78 | ->method('log') 79 | ->will($this->returnCallback($this->collectLogsForAssertion)); 80 | 81 | Validator::doesUserMeetAudienceConditions($this->config, $experiment, $userAttributes, $this->loggerMock); 82 | 83 | $this->assertContains([Logger::DEBUG, "Evaluating audiences for experiment \"test_experiment\": [\"11155\"]."], $this->collectedLogs); 84 | $this->assertContains( 85 | [Logger::DEBUG, "Starting to evaluate audience \"11155\" with conditions: [\"and\",[\"or\",[\"or\",{\"name\":\"browser_type\",\"type\":\"custom_attribute\",\"value\":\"chrome\"}]]]."], 86 | $this->collectedLogs 87 | ); 88 | $this->assertContains([Logger::DEBUG, "Audience \"11155\" evaluated to UNKNOWN."], $this->collectedLogs); 89 | $this->assertContains([Logger::INFO, "Audiences for experiment \"test_experiment\" collectively evaluated to FALSE."], $this->collectedLogs); 90 | } 91 | 92 | public function testIsUserInExperimenEvaluatesAudienceConditions() 93 | { 94 | $experiment = $this->typedConfig->getExperimentFromKey('audience_combinations_experiment'); 95 | $experiment->setAudienceIds([]); 96 | $experiment->setAudienceConditions(['or', ['or', '3468206642', '3988293898']]); 97 | 98 | $this->loggerMock->expects($this->any()) 99 | ->method('log') 100 | ->will($this->returnCallback($this->collectLogsForAssertion)); 101 | 102 | list($result, $reasons) = Validator::doesUserMeetAudienceConditions($this->typedConfig, $experiment, ["house" => "I am in Slytherin"], $this->loggerMock); 103 | 104 | $this->assertContains( 105 | [Logger::DEBUG, "Evaluating audiences for experiment \"audience_combinations_experiment\": [\"or\",[\"or\",\"3468206642\",\"3988293898\"]]."], 106 | $this->collectedLogs 107 | ); 108 | $this->assertContains( 109 | [Logger::DEBUG, "Starting to evaluate audience \"3468206642\" with conditions: [\"and\",[\"or\",[\"or\",{\"name\":\"house\",\"type\":\"custom_attribute\",\"value\":\"Gryffindor\"}]]]."], 110 | $this->collectedLogs 111 | ); 112 | $this->assertContains( 113 | [Logger::DEBUG, "Audience \"3468206642\" evaluated to FALSE."], 114 | $this->collectedLogs 115 | ); 116 | $this->assertContains( 117 | [Logger::DEBUG, "Starting to evaluate audience \"3988293898\" with conditions: [\"and\",[\"or\",[\"or\",{\"name\":\"house\",\"type\":\"custom_attribute\",\"match\":\"substring\",\"value\":\"Slytherin\"}]]]."], 118 | $this->collectedLogs 119 | ); 120 | $this->assertContains( 121 | [Logger::DEBUG, "Audience \"3988293898\" evaluated to TRUE."], 122 | $this->collectedLogs 123 | ); 124 | 125 | $evalCombinedAudienceMessage = "Audiences for experiment \"audience_combinations_experiment\" collectively evaluated to TRUE."; 126 | 127 | $this->assertContains([Logger::INFO, $evalCombinedAudienceMessage], $this->collectedLogs); 128 | $this->assertContains($evalCombinedAudienceMessage, $reasons); 129 | $this->assertCount(1, $reasons); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /tests/UtilsTests/VariableTypeUtilsTest.php: -------------------------------------------------------------------------------- 1 | <?php 2 | /** 3 | * Copyright 2017, 2023 Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | namespace Optimizely\Tests; 19 | 20 | use Monolog\Logger; 21 | use Optimizely\ErrorHandler\NoOpErrorHandler; 22 | use Optimizely\Logger\NoOpLogger; 23 | use Optimizely\Utils\VariableTypeUtils; 24 | use PHPUnit\Framework\TestCase; 25 | 26 | class VariableTypeUtilsTest extends TestCase 27 | { 28 | protected $loggerMock; 29 | protected $variableUtilObj; 30 | 31 | protected function setUp() : void 32 | { 33 | // Mock Logger 34 | $this->loggerMock = $this->getMockBuilder(NoOpLogger::class) 35 | ->setMethods(array('log')) 36 | ->getMock(); 37 | 38 | $this->variableUtilObj = new VariableTypeUtils(); 39 | } 40 | 41 | public function testValueCastingToBoolean() 42 | { 43 | $this->assertTrue($this->variableUtilObj->castStringToType('true', 'boolean')); 44 | $this->assertTrue($this->variableUtilObj->castStringToType('True', 'boolean')); 45 | $this->assertFalse($this->variableUtilObj->castStringToType('false', 'boolean')); 46 | $this->assertFalse($this->variableUtilObj->castStringToType('somestring', 'boolean')); 47 | } 48 | 49 | public function testValueCastingToInteger() 50 | { 51 | $this->assertSame(1000, $this->variableUtilObj->castStringToType('1000', 'integer')); 52 | $this->assertSame(123, $this->variableUtilObj->castStringToType('123', 'integer')); 53 | 54 | // should return nulll and log a message if value can not be casted to an integer 55 | $value = '123.5'; // any string with non-decimal digits 56 | $type = 'integer'; 57 | $this->loggerMock->expects($this->exactly(1)) 58 | ->method('log') 59 | ->with( 60 | Logger::ERROR, 61 | "Unable to cast variable value '{$value}' to type '{$type}'." 62 | ); 63 | 64 | $this->assertNull($this->variableUtilObj->castStringToType($value, $type, $this->loggerMock)); 65 | } 66 | 67 | public function testValueCastingToDouble() 68 | { 69 | $this->assertSame(1000.0, $this->variableUtilObj->castStringToType('1000', 'double')); 70 | $this->assertSame(3.0, $this->variableUtilObj->castStringToType('3.0', 'double')); 71 | $this->assertSame(13.37, $this->variableUtilObj->castStringToType('13.37', 'double')); 72 | 73 | // should return nil and log a message if value can not be casted to a double 74 | $value = 'any-non-numeric-string'; 75 | $type = 'double'; 76 | $this->loggerMock->expects($this->exactly(1)) 77 | ->method('log') 78 | ->with( 79 | Logger::ERROR, 80 | "Unable to cast variable value '{$value}' to type '{$type}'." 81 | ); 82 | 83 | $this->assertNull($this->variableUtilObj->castStringToType($value, $type, $this->loggerMock)); 84 | } 85 | 86 | public function testValueCastingToString() 87 | { 88 | $this->assertSame('13.37', $this->variableUtilObj->castStringToType('13.37', 'string')); 89 | $this->assertSame('a string', $this->variableUtilObj->castStringToType('a string', 'string')); 90 | $this->assertSame('3', $this->variableUtilObj->castStringToType('3', 'string')); 91 | $this->assertSame('false', $this->variableUtilObj->castStringToType('false', 'string')); 92 | } 93 | } 94 | --------------------------------------------------------------------------------