Skip to content

Commit 1694636

Browse files
LaunchDarklyReleaseBoteli-darklyhroederldLaunchDarklyCIbwoskow-ld
authored
prepare 5.1.0 release (#171)
* typo * linter * fix namespaces * fix tests * doc fixes * move a bunch more stuff * misc cleanup * add test for not having any flags * restore documentation for deprecated properties * version 3.5.0 * revert accidental commit * add experimentation event overrides for rules and fallthrough * linter * misc fixes * misc test fixes * Hr/ch34492/waitonconsul (#39) * add step to wait on Consul * coerce user attributes to strings when necessary, don't send events without valid users * explanatory comments * add release script (version update only) * use newer readme footer format * support metric value in track() * linter * update method description * add param to skip db tests, update docs for new repo name * wrong method name * add tests for rollout calculations, + misc test cleanup * misc doc fixes * misc doc fixes * update package name (#45) * add test for cached get all * typo * revert bugfix to test the test * reinstate bugfix * mix fixes, rename file * fix filename * misc cleanup * linter * misc fixes * test state cleanup * linter + fix filename in instructions * misc CI fixes, don't try to install phpredis in 5.6 * don't let user fall outside of last bucket in rollout * PHP 5.5 requires even null properties to be defined * minor cleanup * more accurate changelog text regarding phpredis * Add circle jobs for newer PHP versions. * Revert "Add circle jobs for newer PHP versions." This reverts commit 8939cb2. * implement doc generation with phpDocumentor 3 (prerelease), clean up doc tags (#50) * Add CI jobs for PHP 7.3 + 7.4 (#51) * ensure events aren't sent if send_events is false * clarify test with comment * make prefix concatenation in DynamoDB consistent with other SDKs * fix test * fix PHP 5.5 CI build by pinning Composer version (#54) * Updating warning log in Identify to not say Track was called (#56) * Removed the guides link * add alias functionality and some related tests * Revert "add alias functionality and some related tests" This reverts commit 2bf1cba. * add alias events support (#57) * add alias function to LDClient * add `contextKind` to events that require the new field * add tests for alias and contextKind * merge exp-alloc * drop support for EOL php versions and update deps (#60) * fix test class * remove database integrations from SDK (#63) * add type hints to FeatureRequesterBase methods * fix PHPRedis logic for prefix & custom client, add unit tests (#64) * add psalm lints and php hints (#62) * remove deprecated members (#65) * change default base URL to sdk.launchdarkly.com * move non-public classes into Impl namespace (#66) * add CI job for PHP 8.0 (#69) * use phpDocumentor 3 + misc doc comment cleanup (#68) * Updates docs URLs * pin Psalm to 4.9.2 to prevent a spurious linting error (#71) * use Releaser v2 config + add badge links in readme (#72) * use Releaser v2 config + add badge links in readme * fix badge URL * use Releaser PHP project template (#73) * use Releaser PHP project template * exclude implementation classes from docs * remove obsolete line that's no longer used because $seed is computed elsewhere * remove obsolete VERSION file * Fix test confirming send_events = false is honored (#78) * Minor cleanup and consistency changes (#79) * Add integration test for curl event publisher (#77) * Curl honor connect_timeout (#81) * Set required connect_timeout option in test (#82) * Add Windows support for "Curl" publisher (#80) * Add cs-check to build process (#83) * Don't treat numeric strings as numbers (#84) * Decrease psalm error level (#85) * added TestData, FlagBuilder; added TestDataTest; started implementing FlagBuilder methods * made props protected, made basic build method, made variations method with tests * continued implementing test data and tests for test data * implemented varationForAllUsers, valueForAllUsers, and variationForUsers along with corresponding tests * reorganized functions, added needed classes and functions, left some bodys blank to complete later, implemeted others, organized tests, added missing assertions * broken - transitioning build to return a FeatureFlag, finished implementing some methods * reverted build to return array, implemented getFeature and getAllFeatures methods in FeatureRequester interface for TestData * fixed build, implemented FeatureRequester, added simple test case * Event attribute filtering is overly aggressively (#86) If you try to create a custom attribute with a value of 0, our event serialization code would filter that out because `0 != null` is false. However, it is reasonable to expect that a user might want to provide the value of 0 as a custom value. The code has been updated to only exclude explicitly null values. * Account for traffic allocation on all flags (#87) * finished FlagRuleBuilder implementation; fixed psalm errors; improved comment blocks to adhere better to phpdoc; fixed formatting errors in both TestData and TestDataTest * fixed php-cs-fixer warnings in TestDataTest.php * Apply suggestions from code review Co-authored-by: Matthew M. Keeler <[email protected]> * replace use of array_push with append operator; standardized capitalization of booleans including in code blogs; other formatting adjustments * remove array_splice() implementation of existing user key removal due to breakage in unit tests * converted variationForUser to use array_splice but fixed issue caused by pass by reference instead of pass by value * fixed missing indexes required to decode FlagBuilder into a FeatureFlag using the decode() method * split off TestData\FlagBuilder and TestData\FlagRuleBuilder from TestData; add test coverage for TestData class * additional cleanup; added missing type hint; minor refactoring * remove special handling of singleton arrays in FlagBuilder::variations() * run php-cs-fixer on TestData-related files * started writing repetitive tests using the phpunit @dataProvider feature * swapped positions of expected and actual in dataProvider-driven test * fix typos in code in comment blocks * Apply whitespace fixes from code review Co-authored-by: Matthew M. Keeler <[email protected]> * split unwieldy tests in TestDataTest into separate tests; address TODO item * added annotations to dataProvider-driven tests * changed _isBooleanFlag() implementation to use strict equality * Add unit test to verify `in` operator in TestData (#89) * Add support for psr/log 2 and 3 (#91) * Adds link to Relay Proxy docs * master -> main * Add support for Guzzle 6.3 (#93) * Use setVersion on update of a changed flag (#161) - in TestData::update when flag is being copied from previous version - use setVersion rather than ['version'] to avoid generated error - associated unit test to update an initial flag, change the flag and update it again - unit-tested using docker for php 7.3, 7.4, 8.0, 8.1 Co-authored-by: Colin Henwood <[email protected]> * Add support for monolog 3.0 (#94) * fix base URI concatenation so path isn't lost * fix JSON output for empty allFlagsState result * lint * also fix base URIs for events * fix JSON output for empty allFlagsState result (#97) * fix base URI concatenation so path isn't lost (#96) * fix base URI concatenation so path isn't lost * also fix base URIs for events * disallow non-strings in semver comparisons (#98) * implement contract test service (#95) * (5.0) fix date parsing to disallow invalid types and formats (#99) * fix date parsing to disallow invalid types and formats * lint * change test service to not require Docker, enable tests in CI (#100) * remove alias events (#101) * (U2C #1) implement context type (without attribute references) (#102) * (U2C #2) basic changes to use contexts in evaluations instead of users (#103) * (U2C #3) update CI, release configuration, and dev dependencies for min PHP version of 8.0 (#104) * update CI, release configuration, and dev dependencies for min PHP version of 8.0- * require more recent php-cs-fixer * (U2C #4) use PHP 8 type declarations and strict mode (#105) * (U2C #5) misc syntax cleanup to take advantage of modern language features (#106) * (U2C 6) factor evaluation logic out of model classes (#107) * (U2C #7) support contextKind in clauses (#108) * (U2C #8) support contextTargets (#109) * (U2C #9) support contextKind in rollouts/experiments (#110) * (U2C #10) support includedContexts/excludedContexts in segment (#111) * support attribute reference lookups in evaluations * misc fixes * move AttributeReference class and create instances of it * lint * improve error handling/logging in evaluations * misc fixes * fix exception string conversion * (U2C #11) support attribute reference lookups in evaluations (#112) * support attribute reference lookups in evaluations * misc fixes * move AttributeReference class and create instances of it * lint * comment * revert unnecessary change * update all event logic for U2C * (U2C #12) improve error handling/logging in evaluations (#113) * coalesce operator makes Elvis operator redundant * more coalesce * (U2C #13) update all event logic for U2C (#114) * remove LDUser and LDUserBuilder (#115) * (U2C #15) implement prerequisite cycle detection (#120) * (U2C #16) implement segment recursion and segment cycle detection (#117) * remove LDUser and LDUserBuilder * implement prerequisite cycle detection * lint * rm unused * rm debugging * implement segment recursion and segment cycle detection * (U2C #17) make AttributeReference public in new Types namespace (#118) * (U2C #18) move EventPublisher & FeatureRequester out of main namespace (#119) * (U2C #19) remove deprecated things, clean up tests (#121) * re-add LDUser, allow SDK to accept it interchangeably with LDContext * doc comment improvements * fix custom attribute validation for old users * fix user conversion * update TestData API to use context kinds (#123) * Add application info support (#124) In the 5.x branch, we introduce the Types namespace. To avoid shuffling this file around between versions, we are creating it now in the 4.x branch. * Mark 4.x as deployable branch (#169) * Add application info support (#124) (#125) In the 5.x branch, we introduce the Types namespace. To avoid shuffling this file around between versions, we are creating it now in the 4.x branch. * prepare 4.3.0 release (#170) * cache flag data in allFlags * rm unused imports * add option to reduce front-end metadata for untracked flags * add ability to load flags from a file * linter * data completeness * more data fixes * more data fixes * more data fixes * readme link * rm unused parameters * fix incorrect doc comment * add DynamoDB integration * fix test config * fix string check * readme * fix test data * factor out base class, implement caching, make configuration simpler * fix comment * rm unused const * can't scope constants * linter * add Consul integration * typo * regenerate lockfile using PHP 5.5 * we need at least version 2.1 of the Consul package * update lockfile * rm comment * remove lockfile * add delay for creating test table * move feature requester code into Integrations namespace * linter * misc test fixes * fix apc/apcu calls * fix comment * fix deprecated caching store classes * better caching abstraction * typo * linter * fix namespaces * fix tests * doc fixes * move a bunch more stuff * misc cleanup * add test for not having any flags * restore documentation for deprecated properties * version 3.5.0 * revert accidental commit * add experimentation event overrides for rules and fallthrough * linter * misc fixes * misc test fixes * Hr/ch34492/waitonconsul (#39) * add step to wait on Consul * coerce user attributes to strings when necessary, don't send events without valid users * explanatory comments * add release script (version update only) * use newer readme footer format * support metric value in track() * linter * update method description * add param to skip db tests, update docs for new repo name * wrong method name * add tests for rollout calculations, + misc test cleanup * misc doc fixes * misc doc fixes * update package name (#45) * add test for cached get all * typo * revert bugfix to test the test * reinstate bugfix * mix fixes, rename file * fix filename * misc cleanup * linter * misc fixes * test state cleanup * linter + fix filename in instructions * misc CI fixes, don't try to install phpredis in 5.6 * don't let user fall outside of last bucket in rollout * PHP 5.5 requires even null properties to be defined * minor cleanup * more accurate changelog text regarding phpredis * Add circle jobs for newer PHP versions. * Revert "Add circle jobs for newer PHP versions." This reverts commit 8939cb2. * implement doc generation with phpDocumentor 3 (prerelease), clean up doc tags (#50) * Add CI jobs for PHP 7.3 + 7.4 (#51) * ensure events aren't sent if send_events is false * clarify test with comment * make prefix concatenation in DynamoDB consistent with other SDKs * fix test * fix PHP 5.5 CI build by pinning Composer version (#54) * Updating warning log in Identify to not say Track was called (#56) * Removed the guides link * add alias functionality and some related tests * Revert "add alias functionality and some related tests" This reverts commit 2bf1cba. * add alias events support (#57) * add alias function to LDClient * add `contextKind` to events that require the new field * add tests for alias and contextKind * merge exp-alloc * drop support for EOL php versions and update deps (#60) * fix test class * remove database integrations from SDK (#63) * add type hints to FeatureRequesterBase methods * fix PHPRedis logic for prefix & custom client, add unit tests (#64) * add psalm lints and php hints (#62) * remove deprecated members (#65) * change default base URL to sdk.launchdarkly.com * move non-public classes into Impl namespace (#66) * add CI job for PHP 8.0 (#69) * use phpDocumentor 3 + misc doc comment cleanup (#68) * Updates docs URLs * pin Psalm to 4.9.2 to prevent a spurious linting error (#71) * use Releaser v2 config + add badge links in readme (#72) * use Releaser v2 config + add badge links in readme * fix badge URL * use Releaser PHP project template (#73) * use Releaser PHP project template * exclude implementation classes from docs * remove obsolete line that's no longer used because $seed is computed elsewhere * remove obsolete VERSION file * Fix test confirming send_events = false is honored (#78) * Minor cleanup and consistency changes (#79) * Add integration test for curl event publisher (#77) * Curl honor connect_timeout (#81) * Set required connect_timeout option in test (#82) * Add Windows support for "Curl" publisher (#80) * Add cs-check to build process (#83) * Don't treat numeric strings as numbers (#84) * Decrease psalm error level (#85) * added TestData, FlagBuilder; added TestDataTest; started implementing FlagBuilder methods * made props protected, made basic build method, made variations method with tests * continued implementing test data and tests for test data * implemented varationForAllUsers, valueForAllUsers, and variationForUsers along with corresponding tests * reorganized functions, added needed classes and functions, left some bodys blank to complete later, implemeted others, organized tests, added missing assertions * broken - transitioning build to return a FeatureFlag, finished implementing some methods * reverted build to return array, implemented getFeature and getAllFeatures methods in FeatureRequester interface for TestData * fixed build, implemented FeatureRequester, added simple test case * Event attribute filtering is overly aggressively (#86) If you try to create a custom attribute with a value of 0, our event serialization code would filter that out because `0 != null` is false. However, it is reasonable to expect that a user might want to provide the value of 0 as a custom value. The code has been updated to only exclude explicitly null values. * Account for traffic allocation on all flags (#87) * finished FlagRuleBuilder implementation; fixed psalm errors; improved comment blocks to adhere better to phpdoc; fixed formatting errors in both TestData and TestDataTest * fixed php-cs-fixer warnings in TestDataTest.php * Apply suggestions from code review Co-authored-by: Matthew M. Keeler <[email protected]> * replace use of array_push with append operator; standardized capitalization of booleans including in code blogs; other formatting adjustments * remove array_splice() implementation of existing user key removal due to breakage in unit tests * converted variationForUser to use array_splice but fixed issue caused by pass by reference instead of pass by value * fixed missing indexes required to decode FlagBuilder into a FeatureFlag using the decode() method * split off TestData\FlagBuilder and TestData\FlagRuleBuilder from TestData; add test coverage for TestData class * additional cleanup; added missing type hint; minor refactoring * remove special handling of singleton arrays in FlagBuilder::variations() * run php-cs-fixer on TestData-related files * started writing repetitive tests using the phpunit @dataProvider feature * swapped positions of expected and actual in dataProvider-driven test * fix typos in code in comment blocks * Apply whitespace fixes from code review Co-authored-by: Matthew M. Keeler <[email protected]> * split unwieldy tests in TestDataTest into separate tests; address TODO item * added annotations to dataProvider-driven tests * changed _isBooleanFlag() implementation to use strict equality * Add unit test to verify `in` operator in TestData (#89) * Add support for psr/log 2 and 3 (#91) * Adds link to Relay Proxy docs * master -> main * Add support for Guzzle 6.3 (#93) * Use setVersion on update of a changed flag (#161) - in TestData::update when flag is being copied from previous version - use setVersion rather than ['version'] to avoid generated error - associated unit test to update an initial flag, change the flag and update it again - unit-tested using docker for php 7.3, 7.4, 8.0, 8.1 Co-authored-by: Colin Henwood <[email protected]> * Add support for monolog 3.0 (#94) * fix base URI concatenation so path isn't lost * fix JSON output for empty allFlagsState result * lint * also fix base URIs for events * fix JSON output for empty allFlagsState result (#97) * fix base URI concatenation so path isn't lost (#96) * fix base URI concatenation so path isn't lost * also fix base URIs for events * implement contract test service (#95) * change test service to not require Docker, enable tests in CI (#100) * Add application info support (#124) In the 5.x branch, we introduce the Types namespace. To avoid shuffling this file around between versions, we are creating it now in the 4.x branch. --------- Co-authored-by: Eli Bishop <[email protected]> Co-authored-by: Eli Bishop <[email protected]> Co-authored-by: hroederld <[email protected]> Co-authored-by: LaunchDarklyCI <[email protected]> Co-authored-by: Ben Woskow <[email protected]> Co-authored-by: Ben Woskow <[email protected]> Co-authored-by: Gavin Whelan <[email protected]> Co-authored-by: elliot <[email protected]> Co-authored-by: Elliot Haisley <[email protected]> Co-authored-by: Harpo Roeder <[email protected]> Co-authored-by: LaunchDarklyReleaseBot <[email protected]> Co-authored-by: Ember Stevens <[email protected]> Co-authored-by: ember-stevens <[email protected]> Co-authored-by: Matthew M. Keeler <[email protected]> Co-authored-by: charukiewicz <[email protected]> Co-authored-by: Joey Malinowski <[email protected]> Co-authored-by: Christian Charukiewicz <[email protected]> Co-authored-by: Matthew M. Keeler <[email protected]> Co-authored-by: Colin Henwood <[email protected]> Co-authored-by: Colin Henwood <[email protected]> * Releasing version 4.3.0 --------- Co-authored-by: Eli Bishop <[email protected]> Co-authored-by: hroederld <[email protected]> Co-authored-by: LaunchDarklyCI <[email protected]> Co-authored-by: Ben Woskow <[email protected]> Co-authored-by: Ben Woskow <[email protected]> Co-authored-by: Gavin Whelan <[email protected]> Co-authored-by: elliot <[email protected]> Co-authored-by: Elliot Haisley <[email protected]> Co-authored-by: Harpo Roeder <[email protected]> Co-authored-by: LaunchDarklyReleaseBot <[email protected]> Co-authored-by: Ember Stevens <[email protected]> Co-authored-by: ember-stevens <[email protected]> Co-authored-by: Matthew M. Keeler <[email protected]> Co-authored-by: charukiewicz <[email protected]> Co-authored-by: Joey Malinowski <[email protected]> Co-authored-by: Christian Charukiewicz <[email protected]> Co-authored-by: Matthew M. Keeler <[email protected]> Co-authored-by: Colin Henwood <[email protected]> Co-authored-by: Colin Henwood <[email protected]> Co-authored-by: Eli Bishop <[email protected]>
1 parent 7fc3d59 commit 1694636

File tree

11 files changed

+368
-39
lines changed

11 files changed

+368
-39
lines changed

.ldrelease/config.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ publications:
88
- url: https://packagist.org/packages/launchdarkly/server-sdk
99
description: Packagist
1010

11+
branches:
12+
- name: main
13+
description: 5.x
14+
- name: 4.x
15+
1116
jobs:
1217
- docker:
1318
image: ldcircleci/php-sdk-release:4 # Releaser's default for PHP is still php-sdk-release:3, which is PHP 7.x

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

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

5+
## [4.3.0] - 2023-01-31
6+
### Added:
7+
- Introduced support for an `application_info` config property which sets application metadata that may be used in LaunchDarkly analytics or other product features. This does not affect feature flag evaluations.
8+
59
## [5.0.0] - 2023-01-04
610
The latest version of this SDK supports LaunchDarkly's new custom contexts feature. Contexts are an evolution of a previously-existing concept, "users." Contexts let you create targeting rules for feature flags based on a variety of different information, including attributes pertaining to users, organizations, devices, and more. You can even combine contexts to create "multi-contexts."
711

src/LaunchDarkly/Impl/Integrations/CurlEventPublisher.php

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace LaunchDarkly\Impl\Integrations;
66

7+
use LaunchDarkly\Impl\Util;
78
use LaunchDarkly\LDClient;
89
use LaunchDarkly\Subsystems\EventPublisher;
910

@@ -15,7 +16,6 @@
1516
*/
1617
class CurlEventPublisher implements EventPublisher
1718
{
18-
private string $_sdkKey;
1919
private string $_host;
2020
private int $_port;
2121
private string $_path;
@@ -24,10 +24,11 @@ class CurlEventPublisher implements EventPublisher
2424
private int $_connectTimeout;
2525
private bool $_isWindows;
2626

27+
/** @var array<string, string> */
28+
private array $_eventHeaders;
29+
2730
public function __construct(string $sdkKey, array $options = [])
2831
{
29-
$this->_sdkKey = $sdkKey;
30-
3132
$baseUri = $options['events_uri'] ?? null;
3233
if (!$baseUri) {
3334
$baseUri = LDClient::DEFAULT_EVENTS_URI;
@@ -48,6 +49,7 @@ public function __construct(string $sdkKey, array $options = [])
4849
$this->_curl = $options['curl'];
4950
}
5051

52+
$this->_eventHeaders = Util::eventHeaders($sdkKey, $options['application_info'] ?? null);
5153
$this->_connectTimeout = $options['connect_timeout'];
5254
$this->_isWindows = PHP_OS_FAMILY == 'Windows';
5355
}
@@ -79,11 +81,15 @@ private function createCurlArgs(string $payload): string
7981
$scheme = $this->_ssl ? "https://" : "http://";
8082
$args = " -X POST";
8183
$args.= " --connect-timeout " . $this->_connectTimeout;
82-
$args.= " -H 'Content-Type: application/json'";
83-
$args.= " -H " . escapeshellarg("Authorization: " . $this->_sdkKey);
84-
$args.= " -H 'User-Agent: PHPClient/" . LDClient::VERSION . "'";
85-
$args.= " -H 'X-LaunchDarkly-Event-Schema: " . EventPublisher::CURRENT_SCHEMA_VERSION . "'";
86-
$args.= " -H 'Accept: application/json'";
84+
85+
foreach ($this->_eventHeaders as $key => $value) {
86+
if ($key == 'Authorization') {
87+
$args.= " -H " . escapeshellarg("Authorization: " . $value);
88+
} else {
89+
$args.= " -H '$key: $value'";
90+
}
91+
}
92+
8793
$args.= " -d " . escapeshellarg($payload);
8894
$args.= " " . escapeshellarg($scheme . $this->_host . ":" . $this->_port . $this->_path . "/bulk");
8995
return $args;
@@ -101,16 +107,8 @@ private function makeCurlRequest(string $args): bool
101107

102108
private function createPowershellArgs(string $payloadFile): string
103109
{
104-
$headers = [
105-
'Content-Type' => 'application/json',
106-
'Authorization' => $this->_sdkKey,
107-
'User-Agent' => 'PHPClient/' . LDClient::VERSION,
108-
'X-LaunchDarkly-Event-Schema' => EventPublisher::CURRENT_SCHEMA_VERSION,
109-
'Accept' => 'application/json',
110-
];
111-
112110
$headerString = "";
113-
foreach ($headers as $key => $value) {
111+
foreach ($this->_eventHeaders as $key => $value) {
114112
$headerString .= sprintf("'%s'='%s';", $key, $value);
115113
}
116114

src/LaunchDarkly/Impl/Integrations/GuzzleEventPublisher.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,7 @@ public function __construct(string $sdkKey, array $options = [])
3434
$this->_eventsUri = \LaunchDarkly\Impl\Util::adjustBaseUri($baseUri);
3535

3636
$this->_requestOptions = [
37-
'headers' => [
38-
'Content-Type' => 'application/json',
39-
'Authorization' => $this->_sdkKey,
40-
'User-Agent' => 'PHPClient/' . LDClient::VERSION,
41-
'Accept' => 'application/json',
42-
'X-LaunchDarkly-Event-Schema' => strval(EventPublisher::CURRENT_SCHEMA_VERSION)
43-
],
37+
'headers' => Util::eventHeaders($this->_sdkKey, $options['application_info'] ?? null),
4438
'timeout' => $options['timeout'],
4539
'connect_timeout' => $options['connect_timeout']
4640
];

src/LaunchDarkly/Impl/Integrations/GuzzleFeatureRequester.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use LaunchDarkly\Impl\Model\Segment;
1414
use LaunchDarkly\Impl\UnrecoverableHTTPStatusException;
1515
use LaunchDarkly\Impl\Util;
16-
use LaunchDarkly\LDClient;
1716
use LaunchDarkly\Subsystems\FeatureRequester;
1817
use Psr\Log\LoggerInterface;
1918

@@ -48,11 +47,7 @@ public function __construct(string $baseUri, string $sdkKey, array $options)
4847
}
4948

5049
$defaults = [
51-
'headers' => [
52-
'Authorization' => $sdkKey,
53-
'Content-Type' => 'application/json',
54-
'User-Agent' => 'PHPClient/' . LDClient::VERSION
55-
],
50+
'headers' => Util::defaultHeaders($sdkKey, $options['application_info'] ?? null),
5651
'timeout' => $options['timeout'],
5752
'connect_timeout' => $options['connect_timeout'],
5853
'handler' => $stack,

src/LaunchDarkly/Impl/Util.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
use DateTime;
88
use DateTimeZone;
9+
use LaunchDarkly\LDClient;
10+
use LaunchDarkly\Subsystems\EventPublisher;
11+
use LaunchDarkly\Types\ApplicationInfo;
912
use Monolog\Handler\NullHandler;
1013
use Monolog\Logger;
1114
use Psr\Log\LoggerInterface;
@@ -64,4 +67,47 @@ public static function makeNullLogger(): LoggerInterface
6467
{
6568
return new Logger('', [new NullHandler()]);
6669
}
70+
71+
/**
72+
* An array of header name and values that should be used for any request
73+
* made to LaunchDarkly servers.
74+
*
75+
* @param string $sdkKey
76+
* @param ApplicationInfo|null $applicationInfo
77+
* @return array<string, string>
78+
*/
79+
public static function defaultHeaders(string $sdkKey, $applicationInfo): array
80+
{
81+
$headers = [
82+
'Content-Type' => 'application/json',
83+
'Accept' => 'application/json',
84+
'Authorization' => $sdkKey,
85+
'User-Agent' => 'PHPClient/' . LDClient::VERSION,
86+
];
87+
88+
if ($applicationInfo instanceof ApplicationInfo) {
89+
$headerValue = (string) $applicationInfo;
90+
if ($headerValue) {
91+
$headers['X-LaunchDarkly-Tags'] = $headerValue;
92+
}
93+
}
94+
95+
return $headers;
96+
}
97+
98+
/**
99+
* An array of header name and values that should be used for any request
100+
* made to the LaunchDarkly Events API.
101+
*
102+
* @param string $sdkKey
103+
* @param ApplicationInfo|null $applicationInfo
104+
* @return array
105+
*/
106+
public static function eventHeaders(string $sdkKey, $applicationInfo): array
107+
{
108+
$headers = Util::defaultHeaders($sdkKey, $applicationInfo);
109+
$headers['X-LaunchDarkly-Event-Schema'] = EventPublisher::CURRENT_SCHEMA_VERSION;
110+
111+
return $headers;
112+
}
67113
}

src/LaunchDarkly/LDClient.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use LaunchDarkly\Impl\Util;
1717
use LaunchDarkly\Integrations\Guzzle;
1818
use LaunchDarkly\Subsystems\FeatureRequester;
19+
use LaunchDarkly\Types\ApplicationInfo;
1920
use Monolog\Handler\ErrorLogHandler;
2021
use Monolog\Logger;
2122
use Psr\Log\LoggerInterface;
@@ -75,6 +76,7 @@ class LDClient
7576
* Defaults to false.
7677
* - `private_attribute_names`: An optional array of user attribute names to be marked private. Any users sent to LaunchDarkly
7778
* with this configuration active will have attributes with these names removed. You can also set private attributes on a
79+
* - `application_info`: An optional {@see \LaunchDarkly\Types\ApplicationInfo} instance.
7880
* per-user basis in the LDContext builder.
7981
* - Other options may be available depending on any features you are using from the `LaunchDarkly\Integrations` namespace.
8082
*
@@ -120,8 +122,17 @@ public function __construct(string $sdkKey, array $options = [])
120122
$logger = new Logger("LaunchDarkly", [new ErrorLogHandler()]);
121123
$options['logger'] = $logger;
122124
}
125+
126+
/** @var LoggerInterface */
123127
$this->_logger = $options['logger'];
124128

129+
$applicationInfo = $options['application_info'] ?? null;
130+
if ($applicationInfo instanceof ApplicationInfo) {
131+
foreach ($applicationInfo->errors() as $error) {
132+
$this->_logger->warning($error);
133+
}
134+
}
135+
125136
$this->_eventFactoryDefault = new EventFactory(false);
126137
$this->_eventFactoryWithReasons = new EventFactory(true);
127138

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
namespace LaunchDarkly\Types;
4+
5+
/**
6+
* An object that allows configuration of application metadata.
7+
*
8+
* Application metadata may be used in LaunchDarkly analytics or other product
9+
* features, but does not affect feature flag evaluations.
10+
*
11+
* To use these properties, provide an instance of ApplicationInfo in the config
12+
* parameter of the LDClient.
13+
*
14+
* Application values have the following restrictions:
15+
* - Cannot be empty
16+
* - Cannot exceed 64 characters in length
17+
* - Can only contain a-z, A-Z, 0-9, period (.), dash (-), and underscore (_).
18+
*/
19+
final class ApplicationInfo
20+
{
21+
/** @var string|null **/
22+
private $id;
23+
24+
/** @var string|null **/
25+
private $version;
26+
27+
/** @var array **/
28+
private $errors;
29+
30+
public function __construct()
31+
{
32+
$this->id = null;
33+
$this->version = null;
34+
$this->errors = [];
35+
}
36+
37+
/**
38+
* Set the application id metadata identifier.
39+
*/
40+
public function withId(string $id): ApplicationInfo
41+
{
42+
$this->id = $this->validateValue($id, 'id');
43+
44+
return $this;
45+
}
46+
47+
/**
48+
* Set the application version metadata identifier.
49+
*/
50+
public function withVersion(string $version): ApplicationInfo
51+
{
52+
$this->version = $this->validateValue($version, 'version');
53+
54+
return $this;
55+
}
56+
57+
/**
58+
* Retrieve any validation errors that have accumulated as a result of creating this instance.
59+
*/
60+
public function errors(): array
61+
{
62+
return array_values($this->errors);
63+
}
64+
65+
public function __toString(): string
66+
{
67+
$parts = [];
68+
69+
if ($this->id !== null) {
70+
$parts[] = "application-id/{$this->id}";
71+
}
72+
73+
if ($this->version !== null) {
74+
$parts[] = "application-version/{$this->version}";
75+
}
76+
77+
return join(" ", $parts);
78+
}
79+
80+
private function validateValue(string $value, string $label): ?string
81+
{
82+
$value = strval($value);
83+
84+
if ($value === '') {
85+
return null;
86+
}
87+
88+
if (strlen($value) > 64) {
89+
$this->errors[$label] = "Application value for $label was longer than 64 characters and was discarded";
90+
return null;
91+
}
92+
93+
if (preg_match('/[^a-zA-Z0-9._-]/', $value)) {
94+
$this->errors[$label] = "Application value for $label contained invalid characters and was discarded";
95+
return null;
96+
}
97+
98+
return $value;
99+
}
100+
}

tests/Impl/Integrations/CurlEventPublisherTest.php renamed to tests/Impl/Integrations/EventPublisherTest.php

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
use LaunchDarkly\Impl\Integrations;
77
use LaunchDarkly\LDClient;
88
use LaunchDarkly\Subsystems\EventPublisher;
9+
use LaunchDarkly\Types\ApplicationInfo;
910
use PHPUnit\Framework\TestCase;
11+
use Psr\Log\LoggerInterface;
1012

11-
class CurlEventPublisherTest extends TestCase
13+
class EventPublisherTest extends TestCase
1214
{
1315
public function setUp(): void
1416
{
@@ -20,16 +22,35 @@ public function setUp(): void
2022
$client->request('DELETE', 'http://localhost:8080/__admin/requests');
2123
}
2224

23-
public function testSendsCorrectBodyAndHeaders()
25+
public function getEventPublisher(): array
26+
{
27+
/** @var LoggerInterface **/
28+
$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
29+
$appInfo = (new ApplicationInfo())->withId('my-id')->withVersion('my-version');
30+
31+
$config = [
32+
'events_uri' => 'http://localhost:8080',
33+
'timeout' => 3,
34+
'connect_timeout' => 3,
35+
'application_info' => $appInfo,
36+
'logger' => $logger,
37+
];
38+
39+
$curlPublisher = new Integrations\CurlEventPublisher('sdk-key', $config);
40+
$guzzlePublisher = new Integrations\GuzzleEventPublisher('sdk-key', $config);
41+
42+
return [
43+
[$curlPublisher],
44+
[$guzzlePublisher],
45+
];
46+
}
47+
48+
/**
49+
* @dataProvider getEventPublisher
50+
*/
51+
public function testSendsCorrectBodyAndHeaders($publisher)
2452
{
2553
$event = json_encode(["key" => "user-key"]);
26-
$publisher = new Integrations\CurlEventPublisher(
27-
'sdk-key',
28-
[
29-
'events_uri' => 'http://localhost:8080',
30-
'connect_timeout' => 3,
31-
]
32-
);
3354
$publisher->publish($event);
3455

3556
$requests = [];
@@ -67,5 +88,6 @@ public function testSendsCorrectBodyAndHeaders()
6788
$this->assertEquals('sdk-key', $headers['Authorization']);
6889
$this->assertEquals('PHPClient/' . LDClient::VERSION, $headers['User-Agent']);
6990
$this->assertEquals(EventPublisher::CURRENT_SCHEMA_VERSION, $headers['X-LaunchDarkly-Event-Schema']);
91+
$this->assertEquals('application-id/my-id application-version/my-version', $headers['X-LaunchDarkly-Tags']);
7092
}
7193
}

0 commit comments

Comments
 (0)