Skip to content

Commit

Permalink
Merge pull request #12 from splitio/feat/manager
Browse files Browse the repository at this point in the history
add support for manager methods [WIP]
  • Loading branch information
mredolatti authored Sep 19, 2023
2 parents d60d542 + e55534f commit 8797594
Show file tree
Hide file tree
Showing 45 changed files with 1,502 additions and 88 deletions.
7 changes: 6 additions & 1 deletion CHANGES
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
1.2.0 (Sep 19, 2023):
- Add support for Client/GetTreatment(s)WithConfig operations.
- Add support for Manager operations.
- Add default arguments for value & properties in .track()
- Enforce status code validation on rpc responses.

1.1.0 (Sep 6, 2023):
====================
- Fix issue with datetime attributes on php7
- Remove unit tests from autoload
- Add support for .track()
Expand Down
21 changes: 21 additions & 0 deletions examples/manager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

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

use \SplitIO\ThinSdk\Factory;

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

$manager = $factory->manager();
$names = $manager->splitNames();
print_r($names);
var_dump($manager->split($names[0]));
var_dump($manager->splits());
File renamed without changes.
37 changes: 37 additions & 0 deletions examples/treatmentWithConfig.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->getTreatmentWithConfig("key", null, "feature1", ['age' => 22]));
print_r($client->getTreatmentsWithConfig("key", null, ["feature1", "feature2"], ['age' => 22]));
43 changes: 39 additions & 4 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function __construct(Manager $manager, LoggerInterface $logger, ?Impressi
$this->inputValidator = new InputValidator($logger);
}

public function getTreatment(string $key, ?string $bucketingKey, string $feature, ?array $attributes): string
public function getTreatment(string $key, ?string $bucketingKey, string $feature, ?array $attributes = null): string
{
try {
list($treatment, $ilData) = $this->lm->getTreatment($key, $bucketingKey, $feature, $attributes);
Expand All @@ -38,7 +38,7 @@ public function getTreatment(string $key, ?string $bucketingKey, string $feature
}
}

public function getTreatments(string $key, ?string $bucketingKey, array $features, ?array $attributes): array
public function getTreatments(string $key, ?string $bucketingKey, array $features, ?array $attributes = null): array
{
try {
$results = $this->lm->getTreatments($key, $bucketingKey, $features, $attributes);
Expand All @@ -51,11 +51,46 @@ public function getTreatments(string $key, ?string $bucketingKey, array $feature
return $toReturn;
} catch (\Exception $exc) {
$this->logger->error($exc);
return array_reduce($features, function ($r, $k) { $r[$k] = "control"; return $r; }, []);
return array_reduce($features, function ($r, $k) {
$r[$k] = "control";
return $r;
}, []);
}
}

public function track(string $key, string $trafficType, string $eventType, ?float $value, ?array $properties): bool
public function getTreatmentWithConfig(string $key, ?string $bucketingKey, string $feature, ?array $attributes = null): array
{
try {
list($treatment, $ilData, $config) = $this->lm->getTreatmentWithConfig($key, $bucketingKey, $feature, $attributes);
$this->handleListener($key, $bucketingKey, $feature, $attributes, $treatment, $ilData);
return ['treatment' => $treatment, 'config' => $config];
} catch (\Exception $exc) {
$this->logger->error($exc);
return "control";
}
}

public function getTreatmentsWithConfig(string $key, ?string $bucketingKey, array $features, ?array $attributes = null): array
{
try {
$results = $this->lm->getTreatmentsWithConfig($key, $bucketingKey, $features, $attributes);
$toReturn = [];
foreach ($results as $feature => $result) {
list($treatment, $ilData, $config) = $result;
$toReturn[$feature] = ['treatment' => $treatment, 'config' => $config];
$this->handleListener($key, $bucketingKey, $feature, $attributes, $treatment, $ilData);
}
return $toReturn;
} catch (\Exception $exc) {
$this->logger->error($exc);
return array_reduce($features, function ($r, $k) {
$r[$k] = ['treatment' => 'control', 'config' => null];
return $r;
}, []);
}
}

public function track(string $key, string $trafficType, string $eventType, ?float $value = null, ?array $properties = null): bool
{
try {
$properties = $this->inputValidator->validProperties($properties);
Expand Down
4 changes: 3 additions & 1 deletion src/ClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
interface ClientInterface
{
function getTreatment(string $key, ?string $bucketingKey, string $feature, ?array $attributes): string;
function getTreatmentWithConfig(string $key, ?string $bucketingKey, string $feature, ?array $attributes): array;
function getTreatments(string $key, ?string $bucketingKey, array $features, ?array $attributes): array;
function track(string $key, string $trafficType, string $eventType, ?float $value, ?array $properties): bool;
function getTreatmentsWithConfig(string $key, ?string $bucketingKey, array $features, ?array $attributes): array;
function track(string $key, string $trafficType, string $eventType, ?float $value = null, ?array $properties = null): bool;
}
53 changes: 53 additions & 0 deletions src/Config/Fallback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace SplitIO\ThinSdk\Config;

use SplitIO\ThinSdk\ClientInterface;
use SplitIO\ThinSdk\ManagerInterface;
use SplitIO\ThinSdk\Fallback\AlwaysControlClient;
use SplitIO\ThinSdk\Fallback\AlwaysEmptyManager;


class Fallback
{
private /*bool*/ $disable;
private /*ClientInterface*/ $customUserClient;
private /*ManagerInterface*/ $customUserManager;

private function __construct(bool $disable, ?ClientInterface $client, ?ManagerInterface $manager)
{
$this->disable = $disable;
$this->customUserClient = $client;
$this->customUserManager = $manager;
}

public function disable(): bool
{
return $this->disable;
}

public function client(): ?ClientInterface
{
return $this->customUserClient;
}

public function manager(): ?ManagerInterface
{
return $this->customUserManager;
}

public static function fromArray(array $config): Fallback
{
$d = self::default();
return new Fallback(
$config['disable'] ?? $d->disable(),
$config['client'] ?? $d->client(),
$config['manager'] ?? $d->manager()
);
}

public static function default(): Fallback
{
return new Fallback(false, new AlwaysControlClient(), new AlwaysEmptyManager());
}
}
11 changes: 10 additions & 1 deletion src/Config/Main.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ class Main
private /*Transfer*/ $transfer;
private /*Serialization*/ $serialization;
private /*Logging*/ $logging;
private /*Fallback*/ $fallback;
private /*Utils*/ $utils;

private function __construct(Transfer $transfer, Serialization $serialization, Logging $logging, Utils $utils)
private function __construct(Transfer $transfer, Serialization $serialization, Logging $logging, Fallback $fallback, Utils $utils)
{
$this->transfer = $transfer;
$this->serialization = $serialization;
$this->logging = $logging;
$this->fallback = $fallback;
$this->utils = $utils;
}

Expand All @@ -32,6 +34,11 @@ public function logging(): Logging
return $this->logging;
}

public function fallback(): Fallback
{
return $this->fallback;
}

public function utils(): Utils
{
return $this->utils;
Expand All @@ -43,6 +50,7 @@ public static function fromArray(array $config): Main
Transfer::fromArray($config['transfer'] ?? []),
Serialization::fromArray($config['serialization'] ?? []),
Logging::fromArray($config['logging'] ?? []),
Fallback::fromArray($config['fallback'] ?? []),
Utils::fromArray($config['utils'] ?? []),
);
}
Expand All @@ -53,6 +61,7 @@ public static function default(): Main
Transfer::default(),
Serialization::default(),
Logging::default(),
Fallback::default(),
Utils::default(),
);
}
Expand Down
33 changes: 31 additions & 2 deletions src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,42 @@ public static function default(): Factory
return new Factory(Config\Main::default());
}

public static function withConfig(array $config): Factory
public static function withConfig(array $config): FactoryInterface
{
return new Factory(Config\Main::fromArray($config));
try {
return new Factory(Config\Main::fromArray($config));
} catch (\Exception $e) {

try {
$parsedConfig = Config\Main::fromArray($config);
if ($parsedConfig->fallback()->disable()) { // fallback disabled, re-throw
throw new Fallback\FallbackDisabledException($e);
}

$logger = Helpers::getLogger($parsedConfig->logging());
$logger->error(sprintf("error instantiating a factory with supplied config (%s). will return a fallback.", $e->getMessage()));
$logger->debug($e);
return new Fallback\GenericFallbackFactory($parsedConfig->fallback()->client(), $parsedConfig->fallback()->manager());
} catch (Fallback\FallbackDisabledException $e) {
// client wants to handle exception himself. re-throw it;
throw $e->wrapped();
} catch (\Exception $e) {
// This branch is virtually unreachable (hence untestable) unless we introduce a bug.
// it's basically a safeguard to prevent the customer app from crashing if we do.
$logger = Helpers::getLogger(Config\Logging::default());
$logger->error(sprintf("error parsing supplied factory config config (%s). will return a fallback.", $e->getMessage()));
return new Fallback\GenericFallbackFactory(new Fallback\AlwaysControlClient(), new Fallback\AlwaysEmptyManager());
}
}
}

public function client(): ClientInterface
{
return new Client($this->linkManager, $this->logger, $this->config->utils()->impressionListener());
}

public function manager(): ManagerInterface
{
return new Manager($this->linkManager, $this->logger);
}
};
1 change: 1 addition & 0 deletions src/FactoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
interface FactoryInterface
{
public function client(): ClientInterface;
public function manager(): ManagerInterface;
};
39 changes: 39 additions & 0 deletions src/Fallback/AlwaysControlClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace SplitIO\ThinSdk\Fallback;

use SplitIO\ThinSdk\ClientInterface;

class AlwaysControlClient implements ClientInterface
{
public function getTreatment(string $key, ?string $bucketingKey, string $feature, ?array $attributes): string
{
return "control";
}

public function getTreatmentWithConfig(string $key, ?string $bucketingKey, string $feature, ?array $attributes): array
{
return ['treatment' => 'control', 'config' => null];
}

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
{
return array_reduce($features, function ($carry, $item) {
$carry[$item] = ['treatment' => 'control', 'config' => null];
return $carry;
}, []);
}

public function track(string $key, string $trafficType, string $eventType, ?float $value = null, ?array $properties = null): bool
{
return false;
}
}
24 changes: 24 additions & 0 deletions src/Fallback/AlwaysEmptyManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace SplitIO\ThinSdk\Fallback;

use SplitIO\ThinSdk\ManagerInterface;
use SplitIO\ThinSdk\SplitView;

class AlwaysEmptyManager implements ManagerInterface
{
public function splitNames(): array
{
return [];
}

public function split(string $name): ?SplitView
{
return null;
}

public function splits(): array
{
return [];
}
}
19 changes: 19 additions & 0 deletions src/Fallback/FallbackDisabledException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace SplitIO\ThinSdk\Fallback;

class FallbackDisabledException extends \Exception
{

private /*\Exception*/ $wrapped;

public function __construct(\Exception $wrapped)
{
$this->wrapped = $wrapped;
}

public function wrapped(): \Exception
{
return $this->wrapped;
}
}
Loading

0 comments on commit 8797594

Please sign in to comment.