Skip to content

Commit

Permalink
Merge pull request #13 from filipgolonka/master
Browse files Browse the repository at this point in the history
Allow to enable feature flag based on request parameters
  • Loading branch information
richardfullmer committed Sep 21, 2016
2 parents 92847c4 + 1d76926 commit b93d48c
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 10 deletions.
60 changes: 54 additions & 6 deletions src/Feature.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
class Feature
{
/**
* @var array
* @var string
*/
private $name;

Expand All @@ -30,6 +30,11 @@ class Feature
*/
private $percentage = 0;

/**
* @var string|null
*/
private $requestParam;

/**
* @param string $name
* @param string|null $settings
Expand All @@ -38,7 +43,13 @@ public function __construct($name, $settings = null)
{
$this->name = $name;
if ($settings) {
list($rawPercentage, $rawUsers, $rawGroups) = explode('|', $settings);
$settings = explode('|', $settings);
if (count($settings) == 4) {
$rawRequestParam = array_pop($settings);
$this->requestParam = $rawRequestParam;
}

list($rawPercentage, $rawUsers, $rawGroups) = $settings;
$this->percentage = (int) $rawPercentage;
$this->users = !empty($rawUsers) ? explode(',', $rawUsers) : array();
$this->groups = !empty($rawGroups) ? explode(',', $rawGroups) : array();
Expand Down Expand Up @@ -79,7 +90,8 @@ public function serialize()
return implode('|', array(
$this->percentage,
implode(',', $this->users),
implode(',', $this->groups)
implode(',', $this->groups),
$this->requestParam,
));
}

Expand Down Expand Up @@ -139,6 +151,22 @@ public function getGroups()
return $this->groups;
}

/**
* @return string|null
*/
public function getRequestParam()
{
return $this->requestParam;
}

/**
* @param string|null $requestParam
*/
public function setRequestParam($requestParam)
{
$this->requestParam = $requestParam;
}

/**
* Clear the feature of all configuration
*/
Expand All @@ -147,22 +175,27 @@ public function clear()
$this->groups = array();
$this->users = array();
$this->percentage = 0;
$this->requestParam = '';
}

/**
* Is the feature active?
*
* @param Rollout $rollout
* @param RolloutUserInterface|null $user
* @param array $requestParameters
* @return bool
*/
public function isActive(Rollout $rollout, RolloutUserInterface $user = null)
public function isActive(Rollout $rollout, RolloutUserInterface $user = null, array $requestParameters = array())
{
if (null == $user) {
return $this->percentage == 100;
return $this->isParamInRequestParams($requestParameters) || $this->percentage == 100;
}

return $this->isUserInPercentage($user) || $this->isUserInActiveUsers($user) || $this->isUserInActiveGroup($user, $rollout);
return $this->isParamInRequestParams($requestParameters) ||
$this->isUserInPercentage($user) ||
$this->isUserInActiveUsers($user) ||
$this->isUserInActiveGroup($user, $rollout);
}

/**
Expand All @@ -174,9 +207,24 @@ public function toArray()
'percentage' => $this->percentage,
'groups' => $this->groups,
'users' => $this->users,
'requestParam' => $this->requestParam,
);
}

/**
* @param array $requestParameters
* @return bool
*/
private function isParamInRequestParams(array $requestParameters)
{
$param = explode('=', $this->requestParam);
$key = array_shift($param);
$value = array_shift($param);

return $key && array_key_exists($key, $requestParameters) &&
(empty($value) || $requestParameters[$key] == $value);
}

/**
* @param RolloutUserInterface $user
* @return bool
Expand Down
32 changes: 29 additions & 3 deletions src/Rollout.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,16 @@ public function defineGroup($group, \Closure $closure)
}

/**
* @param string $feature
* @param string $feature
* @param RolloutUserInterface|null $user
* @param array $requestParameters
* @return bool
*/
public function isActive($feature, RolloutUserInterface $user = null)
public function isActive($feature, RolloutUserInterface $user = null, array $requestParameters = array())
{
$feature = $this->get($feature);

return $feature ? $feature->isActive($this, $user) : false;
return $feature ? $feature->isActive($this, $user, $requestParameters) : false;
}

/**
Expand Down Expand Up @@ -155,6 +156,31 @@ public function deactivatePercentage($feature)
}
}

/**
* @param string $feature
* @param string $requestParam
*/
public function activateRequestParam($feature, $requestParam)
{
$feature = $this->get($feature);
if ($feature) {
$feature->setRequestParam($requestParam);
$this->save($feature);
}
}

/**
* @param string $feature
*/
public function deactivateRequestParam($feature)
{
$feature = $this->get($feature);
if ($feature) {
$feature->setRequestParam('');
$this->save($feature);
}
}

/**
* @param string $group
* @param RolloutUserInterface $user
Expand Down
28 changes: 28 additions & 0 deletions tests/FeatureTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

use Opensoft\Rollout\Feature;

/**
* @author Filip Golonka <filipgolonka@gmail.com>
*/
class FeatureTest extends \PHPUnit_Framework_TestCase
{
public function testParseOldSettingsFormat()
{
$feature = new Feature('chat', '100|4,12|fivesonly');

$this->assertEquals(100, $feature->getPercentage());
$this->assertEquals([4, 12], $feature->getUsers());
$this->assertEquals(['fivesonly'], $feature->getGroups());
}

public function testParseNewSettingsFormat()
{
$feature = new Feature('chat', '100|4,12|fivesonly|FF_facebookIntegration=1');

$this->assertEquals(100, $feature->getPercentage());
$this->assertEquals([4, 12], $feature->getUsers());
$this->assertEquals(['fivesonly'], $feature->getGroups());
$this->assertEquals('FF_facebookIntegration=1', $feature->getRequestParam());
}
}
35 changes: 34 additions & 1 deletion tests/RolloutTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public function testDeactivatingAFeatureCompletely()
$this->rollout->activateGroup('chat', 'fivesonly');
$this->rollout->activateUser('chat', new RolloutUser(51));
$this->rollout->activatePercentage('chat', 100);
$this->rollout->activateRequestParam('chat', 'FF_facebookIntegration=1');
$this->rollout->activate('chat');
$this->rollout->deactivate('chat');

Expand All @@ -84,6 +85,9 @@ public function testDeactivatingAFeatureCompletely()
// it should remove the percentage
$this->assertFalse($this->rollout->isActive('chat', new RolloutUser(24)));

// it should remove the request param
$this->assertFalse($this->rollout->isActive('chat', null, array('FF_facebookIntegration', true)));

// it should be removed globally
$this->assertFalse($this->rollout->isActive('chat'));
}
Expand Down Expand Up @@ -204,6 +208,25 @@ public function testDeactivatingThePercentageOfUsers()
$this->assertFalse($this->rollout->isActive('chat', new RolloutUser(24)));
}

public function testActivatingRequestParam()
{
$this->rollout->activateRequestParam('chat', 'FF_facebookIntegration=1');

$this->assertTrue($this->rollout->isActive('chat', null, ['FF_facebookIntegration' => true]));

$this->assertFalse($this->rollout->isActive('chat', null, ['FF_anotherFeature' => true]));
}

public function testDeactivatingRequestParam()
{
$this->rollout->activateRequestParam('chat', 'FF_facebookIntegration=1');
$this->rollout->deactivateRequestParam('chat');

$this->assertFalse($this->rollout->isActive('chat', null, ['FF_facebookIntegration' => true]));

$this->assertFalse($this->rollout->isActive('chat', null, ['FF_anotherFeature' => true]));
}

public function testDeactivatingTheFeatureGlobally()
{
$this->rollout->activate('chat');
Expand Down Expand Up @@ -232,19 +255,29 @@ public function testGet()
$this->rollout->activateGroup('chat', 'greeters');
$this->rollout->activate('signup');
$this->rollout->activateUser('chat', new RolloutUser(42));
$this->rollout->activateRequestParam('chat', 'FF_facebookIntegration=1');

// it should return the feature object
$feature = $this->rollout->get('chat');
$this->assertContains('caretakers', $feature->getGroups());
$this->assertContains('greeters', $feature->getGroups());
$this->assertEquals(10, $feature->getPercentage());
$this->assertContains(42, $feature->getUsers());
$this->assertEquals(array('groups' => array('caretakers', 'greeters'), 'percentage' => 10, 'users' => array('42')), $feature->toArray());
$this->assertEquals(
array(
'groups' => array('caretakers', 'greeters'),
'percentage' => 10,
'users' => array('42'),
'requestParam' => 'FF_facebookIntegration=1'
),
$feature->toArray()
);

$feature = $this->rollout->get('signup');
$this->assertEmpty($feature->getGroups());
$this->assertEmpty($feature->getUsers());
$this->assertEquals(100, $feature->getPercentage());
$this->assertEmpty($feature->getRequestParam());
}

public function testRemove()
Expand Down

0 comments on commit b93d48c

Please sign in to comment.