Skip to content

Commit 7c43198

Browse files
committed
feat(ffe): Add OpenFeature provider implementation
Add DDTrace\OpenFeature\DataDogProvider that implements the OpenFeature PHP SDK's AbstractProvider interface, wrapping the internal FFE evaluation engine.
1 parent 9f36eb7 commit 7c43198

1 file changed

Lines changed: 126 additions & 0 deletions

File tree

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
3+
namespace DDTrace\OpenFeature;
4+
5+
use DDTrace\FeatureFlags\Provider;
6+
use OpenFeature\implementation\provider\AbstractProvider;
7+
use OpenFeature\implementation\provider\ResolutionDetailsBuilder;
8+
use OpenFeature\interfaces\flags\EvaluationContext;
9+
use OpenFeature\interfaces\provider\Metadata;
10+
use OpenFeature\interfaces\provider\ResolutionDetails as ResolutionDetailsInterface;
11+
12+
/**
13+
* Datadog OpenFeature Provider.
14+
*
15+
* Implements the OpenFeature Provider interface for Datadog's
16+
* Feature Flags and Experimentation (FFE) product.
17+
*
18+
* Usage:
19+
* use OpenFeature\API;
20+
* use DDTrace\OpenFeature\DataDogProvider;
21+
*
22+
* API::setProvider(new DataDogProvider());
23+
* $client = API::getClient();
24+
* $value = $client->getBooleanValue('my-flag', false, $context);
25+
*
26+
* Requires: composer require open-feature/sdk
27+
*/
28+
class DataDogProvider extends AbstractProvider
29+
{
30+
/** @var Provider */
31+
private $ffeProvider;
32+
33+
public function __construct()
34+
{
35+
$this->ffeProvider = Provider::getInstance();
36+
$this->ffeProvider->start();
37+
}
38+
39+
public function getMetadata(): Metadata
40+
{
41+
return new class implements Metadata {
42+
public function getName(): string
43+
{
44+
return 'Datadog';
45+
}
46+
};
47+
}
48+
49+
public function resolveBooleanValue(
50+
string $flagKey,
51+
bool $defaultValue,
52+
?EvaluationContext $context = null
53+
): ResolutionDetailsInterface {
54+
return $this->resolve($flagKey, 'BOOLEAN', $defaultValue, $context);
55+
}
56+
57+
public function resolveStringValue(
58+
string $flagKey,
59+
string $defaultValue,
60+
?EvaluationContext $context = null
61+
): ResolutionDetailsInterface {
62+
return $this->resolve($flagKey, 'STRING', $defaultValue, $context);
63+
}
64+
65+
public function resolveIntegerValue(
66+
string $flagKey,
67+
int $defaultValue,
68+
?EvaluationContext $context = null
69+
): ResolutionDetailsInterface {
70+
return $this->resolve($flagKey, 'INTEGER', $defaultValue, $context);
71+
}
72+
73+
public function resolveFloatValue(
74+
string $flagKey,
75+
float $defaultValue,
76+
?EvaluationContext $context = null
77+
): ResolutionDetailsInterface {
78+
return $this->resolve($flagKey, 'NUMERIC', $defaultValue, $context);
79+
}
80+
81+
public function resolveObjectValue(
82+
string $flagKey,
83+
array $defaultValue,
84+
?EvaluationContext $context = null
85+
): ResolutionDetailsInterface {
86+
return $this->resolve($flagKey, 'JSON', $defaultValue, $context);
87+
}
88+
89+
/**
90+
* @param mixed $defaultValue
91+
*/
92+
private function resolve(
93+
string $flagKey,
94+
string $variationType,
95+
$defaultValue,
96+
?EvaluationContext $context = null
97+
): ResolutionDetailsInterface {
98+
$targetingKey = '';
99+
$attributes = [];
100+
101+
if ($context !== null) {
102+
$targetingKey = $context->getTargetingKey() ?? '';
103+
$attrs = $context->getAttributes();
104+
if ($attrs !== null) {
105+
$attributes = $attrs->toArray();
106+
}
107+
}
108+
109+
$result = $this->ffeProvider->evaluate(
110+
$flagKey,
111+
$variationType,
112+
$defaultValue,
113+
$targetingKey,
114+
$attributes
115+
);
116+
117+
$builder = new ResolutionDetailsBuilder();
118+
$builder->withValue($result['value']);
119+
120+
if (isset($result['reason'])) {
121+
$builder->withReason($result['reason']);
122+
}
123+
124+
return $builder->build();
125+
}
126+
}

0 commit comments

Comments
 (0)