Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d29f2d2
add segment matching logic & ability to get segments from LD
eli-darkly Feb 3, 2018
60dec53
misc fixes
eli-darkly Feb 3, 2018
252f270
misc fixes, tests
eli-darkly Feb 5, 2018
120c7e4
more tests
eli-darkly Feb 6, 2018
d6a9a2b
Merge pull request #17 from launchdarkly/eb/segments
eli-darkly Feb 6, 2018
d16d1b6
Merge branch 'segments'
eli-darkly Feb 21, 2018
d0c46bb
version 3.0.0
eli-darkly Feb 21, 2018
e26219b
migrate to CircleCI 2
eli-darkly Mar 30, 2018
a9e9647
typo
eli-darkly Mar 30, 2018
16dd1f5
sudo
eli-darkly Mar 30, 2018
7d09d53
misc fixes
eli-darkly Mar 30, 2018
917b4f1
fixing integration test
eli-darkly Mar 30, 2018
1e3160d
misc fixes
eli-darkly Mar 30, 2018
d9957d8
misc fixes
eli-darkly Mar 30, 2018
cddd7c0
don't need Apache
eli-darkly Mar 30, 2018
b822335
misc fixes
eli-darkly Mar 30, 2018
0c2b351
add a job to run PHP 5.5
eli-darkly Mar 30, 2018
e79714e
fix syntax
eli-darkly Mar 30, 2018
0df4152
typo
eli-darkly Mar 30, 2018
6b84020
misc fixes
eli-darkly Mar 30, 2018
99ff3dc
try to make 7.2 build work
eli-darkly Mar 30, 2018
52267f2
add JUnit output for integration tests
eli-darkly Mar 30, 2018
07b9b24
Merge pull request #18 from launchdarkly/eb/ch15552/circle2
eli-darkly Mar 30, 2018
847b0a7
remove CodeClimate from readme
eli-darkly Apr 16, 2018
3224f38
add variation index to feature request events
eli-darkly Apr 30, 2018
639a0e7
add more unit tests for flag evaluation
eli-darkly Apr 30, 2018
b94d8c4
Merge pull request #19 from launchdarkly/eb/ch16122/code-climate
eli-darkly Apr 30, 2018
9119093
Merge pull request #20 from launchdarkly/eb/ch16654/variation-index
eli-darkly Apr 30, 2018
92b988a
Merge pull request #21 from launchdarkly/eb/eval-tests
eli-darkly Apr 30, 2018
3d1d538
prepare 3.1.0 release
eli-darkly Apr 30, 2018
ee6ac3c
Merge branch 'master' into 3.1.0
eli-darkly Apr 30, 2018
9b16b6a
get flag properties for event even if user is invalid
eli-darkly May 4, 2018
f87bbc1
typo
eli-darkly May 4, 2018
aed7759
fix Redix key for segment retrieval
eli-darkly May 4, 2018
6210902
Merge pull request #22 from launchdarkly/eb/fix-event-properties
eli-darkly May 4, 2018
a23be99
set event version even if evaluation falls through to default
eli-darkly May 4, 2018
e881e2d
Merge pull request #23 from launchdarkly/eb/event-version-with-default
eli-darkly May 4, 2018
ad86829
Merge branch 'master' into 3.1.0
eli-darkly May 4, 2018
442db7f
update changelog
eli-darkly May 4, 2018
ae6b0bc
Merge branch '3.1.0' of github.com:launchdarkly/php-client into 3.1.0
eli-darkly May 4, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
version: 2

workflows:
version: 2
test:
jobs:
- test-5.5
- test-5.6
- test-7.0
- test-7.1
- test-7.2
- integration-test

php-docker-template: &php-docker-template
steps:
- checkout
- run:
name: install current dependencies
command: composer install --no-progress
- run:
name: run tests with current dependency versions
command: vendor/bin/phpunit --log-junit ~/phpunit/junit.xml --coverage-text tests
- store_test_results:
path: ~/phpunit
- store_artifacts:
path: ~/phpunit
- run:
name: run tests with highest available dependency versions
command: composer update --no-progress && vendor/bin/phpunit tests
- run:
name: run tests with lowest available dependency versions
# we skip this for 7.2 because the lowest compatible version of PHPUnit has a bug:
# https://github.com/sebastianbergmann/comparator/pull/30
command: |
if [[ $CIRCLE_JOB != test-7.2 ]]; then
composer update --prefer-lowest --no-progress && vendor/bin/phpunit tests;
fi

jobs:
test-5.6:
<<: *php-docker-template
docker:
- image: circleci/php:5.6.34-cli-jessie
test-7.0:
<<: *php-docker-template
docker:
- image: circleci/php:7.0.28-cli-jessie
test-7.1:
<<: *php-docker-template
docker:
- image: circleci/php:7.1.15-cli-jessie
test-7.2:
<<: *php-docker-template
docker:
- image: circleci/php:7.2.3-cli-stretch

test-5.5: # CircleCI doesn't provide a Docker image for 5.5
machine:
image: circleci/classic:latest # Ubuntu 14.04
steps:
- run:
name: install PHP and Composer
command: |
sudo apt-get update &&
sudo apt-get install circleci-php-5.5.36 &&
php -r "copy('https://getcomposer.org/installer', '/tmp/composer-setup.php');" &&
sudo php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer
- checkout
- run:
name: update dependencies # the dependencies in composer.lock don't work with 5.5
command: composer update --no-progress
- run:
name: run tests
command: vendor/bin/phpunit --log-junit ~/phpunit/junit.xml --coverage-text tests
- store_test_results:
path: ~/phpunit
- store_artifacts:
path: ~/phpunit

integration-test:
docker:
- image: circleci/php:5.6.34-cli-jessie
- image: redis
steps:
- checkout
- run:
name: setup apcu
command: |
pecl config-set php_ini /usr/local/etc/php/php.ini
yes '' | sudo pecl install -f apcu-4.0.10 || true;
echo "extension=apcu.so" | sudo tee -a /usr/local/etc/php/conf.d/apcu.ini;
echo "apc.enable_cli = 1" | sudo tee -a /usr/local/etc/php/conf.d/apcu.ini
- run: composer update --no-progress
- run: vendor/bin/phpunit --log-junit ~/phpunit/junit.xml integration-tests/LDDFeatureRequesterTest.php
- store_test_results:
path: ~/phpunit
- store_artifacts:
path: ~/phpunit
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to the LaunchDarkly PHP SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).

## [3.1.0] - 2018-04-30
### Added
- Analytics events for feature evaluations now have a `variation` property (the variation index) as well as `value`. This will allow for better performance in future versions of [`ld-relay`](https://github.com/launchdarkly/ld-relay) when it is used with the PHP client.
### Fixed
- Fixed a bug that made segment-based rules always fall through when using `LDDFeatureRequester`.

## [3.0.0] - 2018-02-21
### Added
- Support for a new LaunchDarkly feature: reusable user segments.
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
LaunchDarkly SDK for PHP
===========================

[![Code Climate](https://codeclimate.com/github/launchdarkly/php-client/badges/gpa.svg)](https://codeclimate.com/github/launchdarkly/php-client)

[![Circle CI](https://circleci.com/gh/launchdarkly/php-client.svg?style=svg)](https://circleci.com/gh/launchdarkly/php-client)

Requirements
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.0.0
3.1.0
31 changes: 0 additions & 31 deletions circle.yml

This file was deleted.

1 change: 1 addition & 0 deletions src/LaunchDarkly/CurlEventPublisher.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ private function createArgs($payload)
$args.= " -H 'Content-Type: application/json'";
$args.= " -H " . escapeshellarg("Authorization: " . $this->_sdkKey);
$args.= " -H 'User-Agent: PHPClient/" . LDClient::VERSION . "'";
$args.= " -H 'X-LaunchDarkly-Event-Schema: " . EventPublisher::CURRENT_SCHEMA_VERSION . "'";
$args.= " -H 'Accept: application/json'";
$args.= " -d " . escapeshellarg($payload);
$args.= " " . escapeshellarg($scheme . $this->_host . ":" . $this->_port . $this->_path . "/bulk");
Expand Down
2 changes: 2 additions & 0 deletions src/LaunchDarkly/EventPublisher.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/
interface EventPublisher
{
const CURRENT_SCHEMA_VERSION = 2;

/**
* @param string $sdkKey The SDK key for your account
* @param mixed[] $options Client configuration settings
Expand Down
33 changes: 24 additions & 9 deletions src/LaunchDarkly/FeatureFlag.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,18 @@ public function evaluate($user, $featureRequester)
if ($this->isOn()) {
$result = $this->_evaluate($user, $featureRequester, $prereqEvents);
if ($result !== null) {
return new EvalResult($result, $prereqEvents);
return $result;
}
}
$offVariation = $this->getOffVariationValue();
return new EvalResult($offVariation, $prereqEvents);
$offVariationValue = $this->getOffVariationValue();
return new EvalResult($this->_offVariation, $offVariationValue, $prereqEvents);
}

/**
* @param $user LDUser
* @param $featureRequester FeatureRequester
* @param $events
* @return mixed|null
* @return EvalResult|null
*/
private function _evaluate($user, $featureRequester, &$events)
{
Expand All @@ -120,21 +120,26 @@ private function _evaluate($user, $featureRequester, &$events)
return null;
} elseif ($prereqFeatureFlag->isOn()) {
$prereqEvalResult = $prereqFeatureFlag->_evaluate($user, $featureRequester, $events);
$variation = $prereqFeatureFlag->getVariation($prereq->getVariation());
if ($prereqEvalResult === null || $variation === null || $prereqEvalResult !== $variation) {
$variation = $prereq->getVariation();
if ($prereqEvalResult === null || $variation === null || $prereqEvalResult->getVariation() !== $variation) {
$prereqOk = false;
}
} else {
$prereqOk = false;
}
array_push($events, Util::newFeatureRequestEvent($prereqFeatureFlag->getKey(), $user, $prereqEvalResult, null, $prereqFeatureFlag->getVersion(), $this->_key));
array_push($events, Util::newFeatureRequestEvent($prereqFeatureFlag->getKey(), $user,
$prereqEvalResult === null ? null : $prereqEvalResult->getVariation(),
$prereqEvalResult === null ? null : $prereqEvalResult->getValue(),
null, $prereqFeatureFlag->getVersion(), $this->_key));
} catch (EvaluationException $e) {
$prereqOk = false;
}
}
}
if ($prereqOk) {
return $this->getVariation($this->evaluateIndex($user, $featureRequester));
$variation = $this->evaluateIndex($user, $featureRequester);
$value = $this->getVariation($variation);
return new EvalResult($variation, $value, $events);
}
return null;
}
Expand Down Expand Up @@ -221,6 +226,7 @@ public function isDeleted()

class EvalResult
{
private $_variation = null;
private $_value = null;
/** @var array */
private $_prerequisiteEvents = [];
Expand All @@ -230,12 +236,21 @@ class EvalResult
* @param null $value
* @param array $prerequisiteEvents
*/
public function __construct($value, array $prerequisiteEvents)
public function __construct($variation, $value, array $prerequisiteEvents)
{
$this->_variation = $variation;
$this->_value = $value;
$this->_prerequisiteEvents = $prerequisiteEvents;
}

/**
* @return int
*/
public function getVariation()
{
return $this->_variation;
}

/**
* @return null
*/
Expand Down
3 changes: 2 additions & 1 deletion src/LaunchDarkly/GuzzleEventPublisher.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public function __construct($sdkKey, array $options = array())
'Content-Type' => 'application/json',
'Authorization' => $this->_sdkKey,
'User-Agent' => 'PHPClient/' . LDClient::VERSION,
'Accept' => 'application/json'
'Accept' => 'application/json',
'X-LaunchDarkly-Event-Schema' => strval(EventPublisher::CURRENT_SCHEMA_VERSION)
],
'timeout' => $options['timeout'],
'connect_timeout' => $options['connect_timeout']
Expand Down
30 changes: 17 additions & 13 deletions src/LaunchDarkly/LDClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class LDClient
{
const DEFAULT_BASE_URI = 'https://app.launchdarkly.com';
const DEFAULT_EVENTS_URI = 'https://events.launchdarkly.com';
const VERSION = '3.0.0';
const VERSION = '3.1.0';

/** @var string */
protected $_sdkKey;
Expand Down Expand Up @@ -148,12 +148,7 @@ public function variation($key, $user, $default = false)
}

try {
if (is_null($user) || is_null($user->getKey())) {
$this->_sendFlagRequestEvent($key, $user, $default, $default);
$this->_logger->warning("Variation called with null user or null user key! Returning default value");
return $default;
}
if ($user->isKeyBlank()) {
if (!is_null($user) && $user->isKeyBlank()) {
$this->_logger->warning("User key is blank. Flag evaluation will proceed, but the user will not be stored in LaunchDarkly.");
}
try {
Expand All @@ -164,7 +159,12 @@ public function variation($key, $user, $default = false)
}

if (is_null($flag)) {
$this->_sendFlagRequestEvent($key, $user, $default, $default);
$this->_sendFlagRequestEvent($key, $user, null, $default, $default);
return $default;
}
if (is_null($user) || is_null($user->getKey())) {
$this->_sendFlagRequestEvent($key, $user, null, $default, $default, $flag->getVersion());
$this->_logger->warning("Variation called with null user or null user key! Returning default value");
return $default;
}
$evalResult = $flag->evaluate($user, $this->_featureRequester);
Expand All @@ -173,15 +173,18 @@ public function variation($key, $user, $default = false)
$this->_eventProcessor->enqueue($e);
}
}
if ($evalResult->getValue() !== null) {
$this->_sendFlagRequestEvent($key, $user, $evalResult->getValue(), $default, $flag->getVersion());
if ($evalResult !== null && $evalResult->getValue() !== null) {
$this->_sendFlagRequestEvent($key, $user, $evalResult->getVariation(), $evalResult->getValue(), $default, $flag->getVersion());
return $evalResult->getValue();
} else {
$this->_sendFlagRequestEvent($key, $user, null, $default, $default, $flag->getVersion());
return $default;
}
} catch (\Exception $e) {
$this->_logger->error("Caught $e");
}
try {
$this->_sendFlagRequestEvent($key, $user, $default, $default);
$this->_sendFlagRequestEvent($key, $user, null, $default, $default);
} catch (\Exception $e) {
$this->_logger->error("Caught $e");
}
Expand Down Expand Up @@ -326,17 +329,18 @@ public function flush()
/**
* @param $key string
* @param $user LDUser
* @param $variation int | null
* @param $value mixed
* @param $default
* @param $version int | null
* @param string | null $prereqOf
*/
protected function _sendFlagRequestEvent($key, $user, $value, $default, $version = null, $prereqOf = null)
protected function _sendFlagRequestEvent($key, $user, $variation, $value, $default, $version = null, $prereqOf = null)
{
if ($this->isOffline() || !$this->_send_events) {
return;
}
$this->_eventProcessor->enqueue(Util::newFeatureRequestEvent($key, $user, $value, $default, $version, $prereqOf));
$this->_eventProcessor->enqueue(Util::newFeatureRequestEvent($key, $user, $variation, $value, $default, $version, $prereqOf));
}

protected function _get_default($key, $default)
Expand Down
2 changes: 1 addition & 1 deletion src/LaunchDarkly/LDDFeatureRequester.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public function getSegment($key)
$raw = $this->get_from_cache($this->_segments_key, $key);
if ($raw === null) {
$redis = $this->get_connection();
$raw = $redis->hget($this->_features_key, $key);
$raw = $redis->hget($this->_segments_key, $key);
if ($raw) {
$this->store_in_cache($this->_segments_key, $key, $raw);
}
Expand Down
3 changes: 2 additions & 1 deletion src/LaunchDarkly/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ public static function currentTimeUnixMillis()
* @param null $prereqOf string | null
* @return array
*/
public static function newFeatureRequestEvent($key, $user, $value, $default, $version = null, $prereqOf = null)
public static function newFeatureRequestEvent($key, $user, $variation, $value, $default, $version = null, $prereqOf = null)
{
$event = array();
$event['user'] = $user;
$event['variation'] = $variation;
$event['value'] = $value;
$event['kind'] = "feature";
$event['creationDate'] = Util::currentTimeUnixMillis();
Expand Down
Loading