Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FlagSets support #20

Merged
merged 36 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e2db61a
Merge branch 'main' of github.com:splitio/php-thin-client
mmelograno Dec 7, 2023
95da73f
added support to treatmentsByFlagSet
mmelograno Dec 21, 2023
847f160
Merge branch 'main' of github.com:splitio/php-thin-client into task/t…
mmelograno Dec 21, 2023
44be35d
fixes
mmelograno Dec 28, 2023
54870d6
added testing coverage
mmelograno Dec 29, 2023
8e8f1f5
added treatmentsByFlagSets
mmelograno Jan 2, 2024
67568f0
added support to sets and defaultTreatment in manager
mmelograno Jan 9, 2024
cdc76c9
Merge branch 'main' of github.com:splitio/php-thin-client
mmelograno Jan 9, 2024
a774876
added tracer
mmelograno Jan 10, 2024
d4077d0
Merge pull request #17 from splitio/task/treatmentsByFlagSet
mmelograno Jan 10, 2024
c9c15bf
Merge branch 'task/flagSets' of github.com:splitio/php-thin-client in…
mmelograno Jan 11, 2024
e86e397
added tracer
mmelograno Jan 11, 2024
e9e14ff
Merge branch 'task/flagSets' of github.com:splitio/php-thin-client in…
mmelograno Jan 12, 2024
e617b6b
Merge pull request #18 from splitio/task/treatmentsByFlagSets
mmelograno Jan 12, 2024
17e231c
Merge branch 'task/flagSets' of github.com:splitio/php-thin-client in…
mmelograno Jan 12, 2024
d9a8934
Merge pull request #19 from splitio/task/managerflagsets
mmelograno Jan 12, 2024
1265288
added cache for bySet evaluation
mmelograno Jan 12, 2024
b9271b1
Merge branch 'task/flagSets' of github.com:splitio/php-thin-client in…
mmelograno Jan 12, 2024
b10f8d0
added cache for flagsets
mmelograno Jan 14, 2024
29f8580
added some comments
mmelograno Jan 14, 2024
08479a0
updated cache methods for flagsets
mmelograno Jan 15, 2024
91b2a6d
removed unused assert
mmelograno Jan 15, 2024
8abebc2
Merge pull request #21 from splitio/task/flagSetsCache
mmelograno Jan 15, 2024
814dc0a
added validation for flagsets
mmelograno Jan 16, 2024
63c8f27
removed duplicates
mmelograno Jan 16, 2024
2f4adc5
added delimiters to refer to logs for flagsets for input passed
mmelograno Jan 16, 2024
cfed211
added empty array in case cache returns null
mmelograno Jan 16, 2024
f0509d9
added coverage for cache and manager;
mmelograno Jan 16, 2024
2682ee9
Merge pull request #22 from splitio/task/inputValidation
mmelograno Jan 23, 2024
8a844e6
Merge branch 'task/flagSets' of github.com:splitio/php-thin-client in…
mmelograno Jan 23, 2024
b63b644
prepared version
mmelograno Jan 23, 2024
4c4f0a3
removed trailling commas for php 7.3
mmelograno Jan 24, 2024
4a09e27
revert composer.lock
mmelograno Jan 24, 2024
9efeb6c
preparing release 1.5.0 for flagSets support
mmelograno Jan 25, 2024
3fb9145
removed unnecesary return of configs for methods that do not require
mmelograno Jan 25, 2024
454ff82
added gha validation
mmelograno Jan 25, 2024
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
10 changes: 10 additions & 0 deletions .github/dependabot.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
version: 2

updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
reviewers:
- "splitio/sdk"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ vendor
.phpunit.cache
coverage.xml
coverage.html/
*.local.php
8 changes: 8 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
1.5.0 (Jan 25, 2024)
- Added support for Flag Sets on the SDK, which enables grouping feature flags and interacting with the group rather than individually (more details in our documentation):
- Added new variations of the get treatment methods to support evaluating flags in given flag set/s.
- getTreatmentsByFlagSet and getTreatmentsByFlagSets
- getTreatmentWithConfigByFlagSets and getTreatmentsWithConfigByFlagSets
- Updated the following SDK manager method to expose flag sets on flag views:
- Added `defaultTreatment` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager.

1.4.0 (Dec 14, 2023):
- Add support for a custom tracer for client methods.
- Support finer granularity on timeouts.
Expand Down
2 changes: 1 addition & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions examples/treatmentsByFlagSet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

require_once '../vendor/autoload.php';

use \SplitIO\ThinSdk\Factory;
use \SplitIO\ThinSdk\Utils\ImpressionListener;
use \SplitIO\ThinSdk\Models\Impression;

class CustomListener implements ImpressionListener
{
public function accept(Impression $i, ?array $a)
{
echo "got an impression for: key=".$i->getKey()
." feat=".$i->getFeature()
." treatment=".$i->getTreatment()
." label=".$i->getLabel()
." cn=".$i->getChangeNumber()
." #attrs=".(($a == null) ? 0 : count($a))."\n";
}
}

$factory = Factory::withConfig([
'transfer' => [
'address' => '../../splitd/splitd.sock',
'type' => 'unix-stream',
],
'logging' => [
'level' => \Psr\Log\LogLevel::INFO,
],
'utils' => [
'impressionListener' => new CustomListener(),
],
]);

$client = $factory->client();
print_r($client->getTreatmentsByFlagSet("key", null, "server_side", ['age' => 22]));
print_r($client->getTreatmentsWithConfigByFlagSet("key", null, "server_side", ['age' => 22]));
37 changes: 37 additions & 0 deletions examples/treatmentsByFlagSets.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

require_once '../vendor/autoload.php';

use \SplitIO\ThinSdk\Factory;
use \SplitIO\ThinSdk\Utils\ImpressionListener;
use \SplitIO\ThinSdk\Models\Impression;

class CustomListener implements ImpressionListener
{
public function accept(Impression $i, ?array $a)
{
echo "got an impression for: key=".$i->getKey()
." feat=".$i->getFeature()
." treatment=".$i->getTreatment()
." label=".$i->getLabel()
." cn=".$i->getChangeNumber()
." #attrs=".(($a == null) ? 0 : count($a))."\n";
}
}

$factory = Factory::withConfig([
'transfer' => [
'address' => '../../splitd/splitd.sock',
'type' => 'unix-stream',
],
'logging' => [
'level' => \Psr\Log\LogLevel::INFO,
],
'utils' => [
'impressionListener' => new CustomListener(),
],
]);

$client = $factory->client();
print_r($client->getTreatmentsByFlagSets("key", null, ["server_side", "backend"], ['age' => 22]));
print_r($client->getTreatmentsWithConfigByFlagSets("key", null, ["server_side", "backend"], ['age' => 22]));
177 changes: 176 additions & 1 deletion src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ public function getTreatmentsWithConfig(string $key, ?string $bucketingKey, arra
$this->tracer->trace(TEF::forStart($method, $id, $this->tracer->includeArgs() ? func_get_args() : []));
$toReturn = $this->cache->getManyWithConfig($key, $features, $attributes);
$features = self::getMissing($toReturn);

if (count($features) == 0) {
return $toReturn;
}
Expand All @@ -156,6 +155,182 @@ public function getTreatmentsWithConfig(string $key, ?string $bucketingKey, arra
}
}

public function getTreatmentsByFlagSet(
string $key,
?string $bucketingKey,
string $flagSet,
?array $attributes
): array {
try {
$id = $this->tracer->makeId();
$method = Tracer::METHOD_GET_TREATMENTS_BY_FLAG_SET;
$this->tracer->trace(TEF::forStart($method, $id, $this->tracer->includeArgs() ? func_get_args() : []));
$flagSet = $this->inputValidator->sanitize($flagSet, 'getTreatmentsByFlagSet');
if (is_null($flagSet)) {
return array();
}
$featuresFromSet = $this->cache->getFeaturesByFlagSets([$flagSet]);
if (!is_null($featuresFromSet)) {
$toReturn = $this->cache->getMany($key, $featuresFromSet, $attributes);
$features = self::getMissing($toReturn);
if (count($features) == 0) {
return $toReturn;
}
}

$this->tracer->trace(TEF::forRPCStart($method, $id));
$results = $this->lm->getTreatmentsByFlagSet($key, $bucketingKey, $flagSet, $attributes);
$this->tracer->trace(TEF::forRPCEnd($method, $id));
$toReturn = array();
foreach ($results as $feature => $result) {
list($treatment, $ilData) = $result;
$toReturn[$feature] = $treatment;
$this->handleListener($key, $bucketingKey, $feature, $attributes, $treatment, $ilData);
}
$this->cache->setFeaturesForFlagSets([$flagSet], array_keys($results));
$this->cache->setMany($key, $attributes, $toReturn);
return $toReturn;
} catch (\Exception $exc) {
$this->tracer->trace(TEF::forException($method, $id, $exc));
$this->logger->error($exc);
return array();
} finally {
$this->tracer->trace(TEF::forEnd($method, $id));
}
}

public function getTreatmentsWithConfigByFlagSet(
string $key,
?string $bucketingKey,
string $flagSet,
?array $attributes = null
): array {
try {
$id = $this->tracer->makeId();
$method = Tracer::METHOD_GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET;
$this->tracer->trace(TEF::forStart($method, $id, $this->tracer->includeArgs() ? func_get_args() : []));
$flagSet = $this->inputValidator->sanitize($flagSet, 'getTreatmentsWithConfigByFlagSet');
if (is_null($flagSet)) {
return array();
}
$featuresFromSet = $this->cache->getFeaturesByFlagSets([$flagSet]);
if (!is_null($featuresFromSet)) {
$toReturn = $this->cache->getManyWithConfig($key, $featuresFromSet, $attributes);
$features = self::getMissing($toReturn);
if (count($features) == 0) {
return $toReturn;
}
}

$this->tracer->trace(TEF::forRPCStart($method, $id));
$results = $this->lm->getTreatmentsWithConfigByFlagSet($key, $bucketingKey, $flagSet, $attributes);
$this->tracer->trace(TEF::forRPCEnd($method, $id));
$toReturn = array();
foreach ($results as $feature => $result) {
list($treatment, $ilData, $config) = $result;
$toReturn[$feature] = ['treatment' => $treatment, 'config' => $config];
$this->handleListener($key, $bucketingKey, $feature, $attributes, $treatment, $ilData);
}
$this->cache->setFeaturesForFlagSets([$flagSet], array_keys($results));
$this->cache->setManyWithConfig($key, $attributes, $toReturn);
return $toReturn;
} catch (\Exception $exc) {
$this->tracer->trace(TEF::forException($method, $id, $exc));
$this->logger->error($exc);
return array();
} finally {
$this->tracer->trace(TEF::forEnd($method, $id));
}
}

public function getTreatmentsByFlagSets(
string $key,
?string $bucketingKey,
array $flagSets,
?array $attributes
): array {
try {
$id = $this->tracer->makeId();
$method = Tracer::METHOD_GET_TREATMENTS_BY_FLAG_SETS;
$this->tracer->trace(TEF::forStart($method, $id, $this->tracer->includeArgs() ? func_get_args() : []));
$flagSets = $this->inputValidator->sanitizeMany($flagSets, 'getTreatmentsByFlagSets');
if (is_null($flagSets)) {
return array();
}
$featuresFromSets = $this->cache->getFeaturesByFlagSets($flagSets);
if (!is_null($featuresFromSets)) {
$toReturn = $this->cache->getMany($key, $featuresFromSets, $attributes);
$features = self::getMissing($toReturn);
if (count($features) == 0) {
return $toReturn;
}
}

$this->tracer->trace(TEF::forRPCStart($method, $id));
$results = $this->lm->getTreatmentsByFlagSets($key, $bucketingKey, $flagSets, $attributes);
$this->tracer->trace(TEF::forRPCEnd($method, $id));
$toReturn = array();
foreach ($results as $feature => $result) {
list($treatment, $ilData) = $result;
$toReturn[$feature] = $treatment;
$this->handleListener($key, $bucketingKey, $feature, $attributes, $treatment, $ilData);
}
$this->cache->setFeaturesForFlagSets($flagSets, array_keys($results));
$this->cache->setMany($key, $attributes, $toReturn);
return $toReturn;
} catch (\Exception $exc) {
$this->tracer->trace(TEF::forException($method, $id, $exc));
$this->logger->error($exc);
return array();
} finally {
$this->tracer->trace(TEF::forEnd($method, $id));
}
}

public function getTreatmentsWithConfigByFlagSets(
string $key,
?string $bucketingKey,
array $flagSets,
?array $attributes = null
): array {
try {
$id = $this->tracer->makeId();
$method = Tracer::METHOD_GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS;
$this->tracer->trace(TEF::forStart($method, $id, $this->tracer->includeArgs() ? func_get_args() : []));
$flagSets = $this->inputValidator->sanitizeMany($flagSets, 'getTreatmentsWithConfigByFlagSets');
if (is_null($flagSets)) {
return array();
}
$featuresFromSet = $this->cache->getFeaturesByFlagSets($flagSets);
if (!is_null($featuresFromSet)) {
$toReturn = $this->cache->getManyWithConfig($key, $featuresFromSet, $attributes);
$features = self::getMissing($toReturn);
if (count($features) == 0) {
return $toReturn;
}
}

$this->tracer->trace(TEF::forRPCStart($method, $id));
$results = $this->lm->getTreatmentsWithConfigByFlagSets($key, $bucketingKey, $flagSets, $attributes);
$this->tracer->trace(TEF::forRPCEnd($method, $id));
$toReturn = array();
foreach ($results as $feature => $result) {
list($treatment, $ilData, $config) = $result;
$toReturn[$feature] = ['treatment' => $treatment, 'config' => $config];
$this->handleListener($key, $bucketingKey, $feature, $attributes, $treatment, $ilData);
}
$this->cache->setFeaturesForFlagSets($flagSets, array_keys($results));
$this->cache->setManyWithConfig($key, $attributes, $toReturn);
return $toReturn;
} catch (\Exception $exc) {
$this->tracer->trace(TEF::forException($method, $id, $exc));
$this->logger->error($exc);
return array();
} finally {
$this->tracer->trace(TEF::forEnd($method, $id));
}
}

public function track(string $key, string $trafficType, string $eventType, ?float $value = null, ?array $properties = null): bool
{
try {
Expand Down
14 changes: 14 additions & 0 deletions src/ClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,19 @@ function getTreatment(string $key, ?string $bucketingKey, string $feature, ?arra
function getTreatmentWithConfig(string $key, ?string $bucketingKey, string $feature, ?array $attributes): array;
function getTreatments(string $key, ?string $bucketingKey, array $features, ?array $attributes): array;
function getTreatmentsWithConfig(string $key, ?string $bucketingKey, array $features, ?array $attributes): array;
function getTreatmentsByFlagSet(string $key, ?string $bucketingKey, string $flagSet, ?array $attributes): array;
function getTreatmentsWithConfigByFlagSet(
string $key,
?string $bucketingKey,
string $flagSet,
?array $attributes
): array;
function getTreatmentsByFlagSets(string $key, ?string $bucketingKey, array $flagSets, ?array $attributes): array;
function getTreatmentsWithConfigByFlagSets(
string $key,
?string $bucketingKey,
array $flagSets,
?array $attributes
): array;
function track(string $key, string $trafficType, string $eventType, ?float $value = null, ?array $properties = null): bool;
}
24 changes: 22 additions & 2 deletions src/Fallback/AlwaysControlClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,42 @@ public function getTreatmentWithConfig(string $key, ?string $bucketingKey, strin
return ['treatment' => 'control', 'config' => null];
}

public function getTreatments(string $key, ?string $bucketingKey, array $features, ?array $attributes): array
public function getTreatments(string $key, ?string $bucketingKey, array $features, ?array $attributes): array
{
return array_reduce($features, function ($carry, $item) {
$carry[$item] = "control";
return $carry;
}, []);
}

public function getTreatmentsWithConfig(string $key, ?string $bucketingKey, array $features, ?array $attributes): array
public function getTreatmentsWithConfig(string $key, ?string $bucketingKey, array $features, ?array $attributes): array
{
return array_reduce($features, function ($carry, $item) {
$carry[$item] = ['treatment' => 'control', 'config' => null];
return $carry;
}, []);
}

public function getTreatmentsByFlagSet(string $key, $bucketingKey, string $flagSet, $attributes): array
{
return array();
}

public function getTreatmentsWithConfigByFlagSet(string $key, $bucketingKey, string $flagSet, $attributes): array
{
return array();
}

public function getTreatmentsByFlagSets(string $key, $bucketingKey, array $flagSets, $attributes): array
{
return array();
}

public function getTreatmentsWithConfigByFlagSets(string $key, $bucketingKey, array $flagSets, $attributes): array
{
return array();
}

public function track(string $key, string $trafficType, string $eventType, ?float $value = null, ?array $properties = null): bool
{
return false;
Expand Down
14 changes: 14 additions & 0 deletions src/Link/Consumer/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ function getTreatment(string $key, ?string $bucketingKey, string $feature, ?arra
function getTreatmentWithConfig(string $key, ?string $bucketingKey, string $feature, ?array $attributes): array;
function getTreatments(string $key, ?string $bucketingKey, array $features, ?array $attributes): array;
function getTreatmentsWithConfig(string $key, ?string $bucketingKey, array $features, ?array $attributes): array;
function getTreatmentsByFlagSet(string $key, ?string $bucketingKey, string $flagSet, ?array $attributes): array;
function getTreatmentsWithConfigByFlagSet(
string $key,
?string $bucketingKey,
string $flagSet,
?array $attributes
): array;
function getTreatmentsByFlagSets(string $key, ?string $bucketingKey, array $flagSets, ?array $attributes): array;
function getTreatmentsWithConfigByFlagSets(
string $key,
?string $bucketingKey,
array $flagSet,
?array $attributes
): array;
function track(string $key, string $trafficType, string $eventType, ?float $value, ?array $properties): bool;
function splitNames(): array;
function split(string $splitName): ?SplitView;
Expand Down
Loading
Loading