Skip to content

Instantly share code, notes, and snippets.

@Grom-S
Created February 11, 2014 14:17
Show Gist options
  • Save Grom-S/8935609 to your computer and use it in GitHub Desktop.
Save Grom-S/8935609 to your computer and use it in GitHub Desktop.
<?php
// Usage example
$testsRunner = new TestsRunner();
$testsRunner->setJsonFileLocation('path/to/tests.json');
$values = $testsRunner->getValues(37, 20, 'us');
[
{
"name": "Example Test",
"conditions": {
"product_id": "0",
"template_id": "0",
"country": "us",
"query": {
"template": "main",
"id": "77"
}
},
"plans": [
{
"ratio": 25,
"values": {
"installer": "setup.exe",
"language": "en"
}
},
{
"ratio": 40,
"values": {
"installer": "setup2.exe",
"size": "large",
"language": "ru"
}
},
{
"ratio": 35,
"values": {
"installer": "setup3.exe",
"size": "small",
"language": "de"
}
}
]
},
{
"name": "Another Test",
"conditions": {
"product_id": "37",
"template_id": "21",
"country": "ru",
"query": null
},
"plans": [
{
"ratio": 23,
"values": {
"param1": "1"
}
},
{
"ratio": 75,
"values": {
"param1": "2"
}
},
{
"ratio": 2,
"values": {
"param1": "3"
}
}
]
}
]
<?php
class TestsRunner
{
private $jsonFilePath;
public function setJsonFileLocation($path)
{
if (!file_exists($path)) {
throw new Exception(sprintf('JSON file "%s" was not found', $path));
}
$this->jsonFilePath = $path;
}
public function getValues($productId, $templateId, $countryCode)
{
if (!$productId) {
throw new Exception('productId parameter is required');
}
if (!$templateId) {
throw new Exception('templateId parameter is required');
}
if (!$countryCode) {
throw new Exception('countryCode parameter is required');
}
try {
$test = $this->findFirstMatchedTest($productId, $templateId, $countryCode);
$winnerPlan = $this->runTest($test);
return $winnerPlan['values'];
}
catch (Exception $e) {
return array();
}
}
private function findFirstMatchedTest($productId, $templateId, $countryCode)
{
$tests = $this->getTestsFromFile();
foreach ($tests as $test) {
if ($this->matches($test, $productId, $templateId, $countryCode)) {
return $test;
}
}
throw new Exception('No tests matched');
}
private function getTestsFromFile()
{
return json_decode(file_get_contents($this->jsonFilePath), true);
}
private function runTest($test)
{
$value = mt_rand(0, 100);
$winnerIndex = 0;
$min = 0;
foreach ($test['plans'] as $index => $plan) {
$planRatio = (int)$plan['ratio'];
$max = $min + $planRatio;
if ($value >= $min && $value <= $max) {
$winnerIndex = $index;
break;
}
$min += $planRatio;
}
return $test['plans'][$winnerIndex];
}
private function matches($test, $productId, $templateId, $countryCode)
{
$conditions = $test['conditions'];
// if there is product constrain in test
if ($conditions['product_id']) {
// and product not matches
if ($productId != $conditions['product_id']) {
return false;
}
}
// if there is template constrain in test
if ($conditions['template_id']) {
// and template not matches
if ($templateId != $conditions['template_id']) {
return false;
}
}
// if there is query constrain in the test
if ($conditions['query']) {
foreach ($conditions['query'] as $paramName => $paramValue) {
if (!isset($_GET[$paramName])) {
return false;
}
if ($_GET[$paramName] != $paramValue) {
return false;
}
}
}
// if there is country constrain in the test
if ($conditions['country']) {
if (strtolower($countryCode) !== strtolower($conditions['country'])) {
return false;
}
}
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment