Skip to content

Commit

Permalink
feat(datafile management): Added Config Update Notification Listener
Browse files Browse the repository at this point in the history
  • Loading branch information
rashidsp committed Aug 27, 2019
1 parent 4d6dbbf commit 64ee66d
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 7 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Optimizely Rollouts is free feature flags for development teams. Easily roll out

### Installing the SDK

The Optimizely PHP SDK can be installed through [Composer](https://getcomposer.org/). Please use the following command:
The Optimizely PHP SDK can be installed through [Composer](https://getcomposer.org/). Please use the following command:

```
php composer.phar require optimizely/optimizely-sdk
Expand Down Expand Up @@ -61,6 +61,8 @@ $configManager = new HTTPProjectConfigManager(<<SDK_KEY>>);
##### SDK key
Optimizely project SDK key; required unless source URL is overridden.

A notification signal will be triggered whenever a _new_ datafile is fetched and Project Config is updated. To subscribe to these notifications, use the `$notificationCenter->addNotificationListener(NotificationType::OPTIMIZELY_CONFIG_UPDATE, $updateCallback)`.

#### Documentation
See the Optimizely Full Stack [developer documentation](https://developers.optimizely.com/x/solutions/sdks/reference/?language=php) to learn how to set up your first Full Stack project and use the SDK.

Expand Down
6 changes: 6 additions & 0 deletions src/Optimizely/Notification/NotificationType.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,17 @@ class NotificationType
*/
const DECISION = "DECISION:type, user_id, attributes, decision_info";

/*
* Notification triggered when Project Config is updated.
*/
const OPTIMIZELY_CONFIG_UPDATE = "optimizely_config_update";

/*
* Notification triggered when a conversion event is sent to Optimizely.
*/
const TRACK = "TRACK:event_key, user_id, attributes, event_tags, event";


public static function isNotificationTypeValid($notification_type)
{
$oClass = new \ReflectionClass(__CLASS__);
Expand Down
22 changes: 19 additions & 3 deletions src/Optimizely/ProjectConfigManager/HTTPProjectConfigManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
use Optimizely\Enums\ProjectConfigManagerConstants;
use Optimizely\ErrorHandler\NoOpErrorHandler;
use Optimizely\Logger\NoOpLogger;
use Optimizely\Notification\NotificationCenter;
use Optimizely\Notification\NotificationType;
use Optimizely\Utils\Validator;

class HTTPProjectConfigManager implements ProjectConfigManagerInterface
Expand Down Expand Up @@ -63,6 +65,11 @@ class HTTPProjectConfigManager implements ProjectConfigManagerInterface
*/
private $_errorHandler;

/**
* @var NotificationCenter NotificationCenter instance.
*/
private $_notificationCenter;

public function __construct(
$sdkKey = null,
$url = null,
Expand All @@ -71,11 +78,16 @@ public function __construct(
$datafile = null,
$skipJsonValidation = false,
$logger = null,
$errorHandler = null
$errorHandler = null,
$notificationCenter = null
) {
$this->_skipJsonValidation = $skipJsonValidation;
$this->_logger = $logger;
$this->_errorHandler = $errorHandler;
$this->_logger = $logger ?: new NoOpLogger();
$this->_errorHandler = $errorHandler ?: new NoOpErrorHandler();
$this->_notificationCenter = $notificationCenter;
if (!($this->_notificationCenter instanceof NotificationCenter)) {
$this->_notificationCenter = new NotificationCenter($this->_logger, $this->_errorHandler);
}
$this->httpClient = new HttpClient();

if ($this->_logger === null) {
Expand Down Expand Up @@ -231,6 +243,10 @@ protected function handleResponse($datafile)
}

$this->_config = $config;

$this->_notificationCenter->sendNotifications(NotificationType::OPTIMIZELY_CONFIG_UPDATE);
$this->_logger->log(Logger::DEBUG, sprintf('Received new datafile and updated config. Old revision number: "%s". New revision number: "%s".', $previousRevision, $this->_config->getRevision()));

return true;
}

Expand Down
28 changes: 25 additions & 3 deletions tests/ProjectConfigManagerTests/HTTPProjectConfigManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
use Optimizely\ErrorHandler\NoOpErrorHandler;
use Optimizely\Exceptions\InvalidDatafileVersionException;
use Optimizely\Logger\NoOpLogger;
use Optimizely\Notification\NotificationCenter;
use Optimizely\Notification\NotificationType;
use Optimizely\ProjectConfigManager\HTTPProjectConfigManager;

class HTTPProjectConfigManagerTest extends \PHPUnit_Framework_TestCase
Expand All @@ -48,6 +50,12 @@ public function setUp()
->setMethods(array('handleError'))
->getMock();

// Mock Notification Center
$this->notificationCenterMock = $this->getMockBuilder(NotificationCenter::class)
->setConstructorArgs(array($this->loggerMock, $this->errorHandlerMock))
->setMethods(array('sendNotifications'))
->getMock();

$this->url = "https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json";
$this->template = "https://cdn.optimizely.com/datafiles/%s.json";
}
Expand Down Expand Up @@ -254,18 +262,26 @@ public function testConfigNotUpdatedWhenDatafileIsNotModified()
$this->assertEquals($config, $configAfterFetch);
}

public function testGetConfigReturnsUpdatedDatafileWhenHttpClientReturnsValidDatafile()
public function testHandleResponseCallsConfigUpdateListenerWhenProjectConfigIsUpdated()
{
$configManagerMock = $this->getMockBuilder(HTTPProjectConfigManagerTester::class)
->setConstructorArgs(array(null, $this->url, null, true, DATAFILE_WITH_TYPED_AUDIENCES, false,
$this->loggerMock, $this->errorHandlerMock))
$this->loggerMock, $this->errorHandlerMock, $this->notificationCenterMock))
->setMethods(array('fetchDatafile'))
->getMock();

$configManagerMock->expects($this->any())
->method('fetchDatafile')
->willReturn(DATAFILE);

$this->loggerMock->expects($this->once())
->method('log')
->with(Logger::DEBUG, 'Received new datafile and updated config. Old revision number: "3". New revision number: "15".');

$this->notificationCenterMock->expects($this->once())
->method('sendNotifications')
->with(NotificationType::OPTIMIZELY_CONFIG_UPDATE);

$configManagerMock->handleResponse(DATAFILE);

$config = DatafileProjectConfig::createProjectConfigFromDatafile(
Expand Down Expand Up @@ -333,13 +349,19 @@ public function testHandleResponseReturnsFalseForSameDatafilesRevisions()
{
$configManagerMock = $this->getMockBuilder(HTTPProjectConfigManagerTester::class)
->setConstructorArgs(array(null, $this->url, null, false, DATAFILE, false,
$this->loggerMock, $this->errorHandlerMock))
$this->loggerMock, $this->errorHandlerMock, $this->notificationCenterMock))
->setMethods(array('fetch'))
->getMock();

$config = $configManagerMock->getConfig();
$datafile = json_decode(DATAFILE, true);

$this->loggerMock->expects($this->never())
->method('log');

$this->notificationCenterMock->expects($this->never())
->method('sendNotifications');

// handleResponse returns False when new Datafile's revision is equal
// to previous revision.
$this->assertSame($config->getRevision(), $datafile['revision']);
Expand Down

0 comments on commit 64ee66d

Please sign in to comment.