Skip to content

Commit 64ee66d

Browse files
committed
feat(datafile management): Added Config Update Notification Listener
1 parent 4d6dbbf commit 64ee66d

File tree

4 files changed

+53
-7
lines changed

4 files changed

+53
-7
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Optimizely Rollouts is free feature flags for development teams. Easily roll out
1414

1515
### Installing the SDK
1616

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

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

64+
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)`.
65+
6466
#### Documentation
6567
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.
6668

src/Optimizely/Notification/NotificationType.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,17 @@ class NotificationType
3232
*/
3333
const DECISION = "DECISION:type, user_id, attributes, decision_info";
3434

35+
/*
36+
* Notification triggered when Project Config is updated.
37+
*/
38+
const OPTIMIZELY_CONFIG_UPDATE = "optimizely_config_update";
39+
3540
/*
3641
* Notification triggered when a conversion event is sent to Optimizely.
3742
*/
3843
const TRACK = "TRACK:event_key, user_id, attributes, event_tags, event";
3944

45+
4046
public static function isNotificationTypeValid($notification_type)
4147
{
4248
$oClass = new \ReflectionClass(__CLASS__);

src/Optimizely/ProjectConfigManager/HTTPProjectConfigManager.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
use Optimizely\Enums\ProjectConfigManagerConstants;
2525
use Optimizely\ErrorHandler\NoOpErrorHandler;
2626
use Optimizely\Logger\NoOpLogger;
27+
use Optimizely\Notification\NotificationCenter;
28+
use Optimizely\Notification\NotificationType;
2729
use Optimizely\Utils\Validator;
2830

2931
class HTTPProjectConfigManager implements ProjectConfigManagerInterface
@@ -63,6 +65,11 @@ class HTTPProjectConfigManager implements ProjectConfigManagerInterface
6365
*/
6466
private $_errorHandler;
6567

68+
/**
69+
* @var NotificationCenter NotificationCenter instance.
70+
*/
71+
private $_notificationCenter;
72+
6673
public function __construct(
6774
$sdkKey = null,
6875
$url = null,
@@ -71,11 +78,16 @@ public function __construct(
7178
$datafile = null,
7279
$skipJsonValidation = false,
7380
$logger = null,
74-
$errorHandler = null
81+
$errorHandler = null,
82+
$notificationCenter = null
7583
) {
7684
$this->_skipJsonValidation = $skipJsonValidation;
77-
$this->_logger = $logger;
78-
$this->_errorHandler = $errorHandler;
85+
$this->_logger = $logger ?: new NoOpLogger();
86+
$this->_errorHandler = $errorHandler ?: new NoOpErrorHandler();
87+
$this->_notificationCenter = $notificationCenter;
88+
if (!($this->_notificationCenter instanceof NotificationCenter)) {
89+
$this->_notificationCenter = new NotificationCenter($this->_logger, $this->_errorHandler);
90+
}
7991
$this->httpClient = new HttpClient();
8092

8193
if ($this->_logger === null) {
@@ -231,6 +243,10 @@ protected function handleResponse($datafile)
231243
}
232244

233245
$this->_config = $config;
246+
247+
$this->_notificationCenter->sendNotifications(NotificationType::OPTIMIZELY_CONFIG_UPDATE);
248+
$this->_logger->log(Logger::DEBUG, sprintf('Received new datafile and updated config. Old revision number: "%s". New revision number: "%s".', $previousRevision, $this->_config->getRevision()));
249+
234250
return true;
235251
}
236252

tests/ProjectConfigManagerTests/HTTPProjectConfigManagerTest.php

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
use Optimizely\ErrorHandler\NoOpErrorHandler;
2828
use Optimizely\Exceptions\InvalidDatafileVersionException;
2929
use Optimizely\Logger\NoOpLogger;
30+
use Optimizely\Notification\NotificationCenter;
31+
use Optimizely\Notification\NotificationType;
3032
use Optimizely\ProjectConfigManager\HTTPProjectConfigManager;
3133

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

53+
// Mock Notification Center
54+
$this->notificationCenterMock = $this->getMockBuilder(NotificationCenter::class)
55+
->setConstructorArgs(array($this->loggerMock, $this->errorHandlerMock))
56+
->setMethods(array('sendNotifications'))
57+
->getMock();
58+
5159
$this->url = "https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json";
5260
$this->template = "https://cdn.optimizely.com/datafiles/%s.json";
5361
}
@@ -254,18 +262,26 @@ public function testConfigNotUpdatedWhenDatafileIsNotModified()
254262
$this->assertEquals($config, $configAfterFetch);
255263
}
256264

257-
public function testGetConfigReturnsUpdatedDatafileWhenHttpClientReturnsValidDatafile()
265+
public function testHandleResponseCallsConfigUpdateListenerWhenProjectConfigIsUpdated()
258266
{
259267
$configManagerMock = $this->getMockBuilder(HTTPProjectConfigManagerTester::class)
260268
->setConstructorArgs(array(null, $this->url, null, true, DATAFILE_WITH_TYPED_AUDIENCES, false,
261-
$this->loggerMock, $this->errorHandlerMock))
269+
$this->loggerMock, $this->errorHandlerMock, $this->notificationCenterMock))
262270
->setMethods(array('fetchDatafile'))
263271
->getMock();
264272

265273
$configManagerMock->expects($this->any())
266274
->method('fetchDatafile')
267275
->willReturn(DATAFILE);
268276

277+
$this->loggerMock->expects($this->once())
278+
->method('log')
279+
->with(Logger::DEBUG, 'Received new datafile and updated config. Old revision number: "3". New revision number: "15".');
280+
281+
$this->notificationCenterMock->expects($this->once())
282+
->method('sendNotifications')
283+
->with(NotificationType::OPTIMIZELY_CONFIG_UPDATE);
284+
269285
$configManagerMock->handleResponse(DATAFILE);
270286

271287
$config = DatafileProjectConfig::createProjectConfigFromDatafile(
@@ -333,13 +349,19 @@ public function testHandleResponseReturnsFalseForSameDatafilesRevisions()
333349
{
334350
$configManagerMock = $this->getMockBuilder(HTTPProjectConfigManagerTester::class)
335351
->setConstructorArgs(array(null, $this->url, null, false, DATAFILE, false,
336-
$this->loggerMock, $this->errorHandlerMock))
352+
$this->loggerMock, $this->errorHandlerMock, $this->notificationCenterMock))
337353
->setMethods(array('fetch'))
338354
->getMock();
339355

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

359+
$this->loggerMock->expects($this->never())
360+
->method('log');
361+
362+
$this->notificationCenterMock->expects($this->never())
363+
->method('sendNotifications');
364+
343365
// handleResponse returns False when new Datafile's revision is equal
344366
// to previous revision.
345367
$this->assertSame($config->getRevision(), $datafile['revision']);

0 commit comments

Comments
 (0)