Skip to content

Commit 5a30f6c

Browse files
Merge pull request #26 from optimizely/devel
Merge into master
2 parents f32e81a + 43412c6 commit 5a30f6c

File tree

10 files changed

+107
-19
lines changed

10 files changed

+107
-19
lines changed

.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ php:
33
- '5.5'
44
- '5.6'
55
- '7.0'
6+
- '7.1'
67
- 'hhvm'
78
before_install:
89
- composer install --dev

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1+
## 1.0.0
2+
- General release of Optimizely X Full Stack PHP SDK. No breaking changes from previous version.
3+
- Introduced curl based event dispatcher.
4+
15
## 0.1.0
26
- Beta release of the Optimizely X Full Stack PHP SDK.

README.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#Optimizely PHP SDK
22
[![Build Status](https://travis-ci.org/optimizely/php-sdk.svg?branch=master)](https://travis-ci.org/optimizely/php-sdk)
33
[![Coverage Status](https://coveralls.io/repos/github/optimizely/php-sdk/badge.svg?branch=master)](https://coveralls.io/github/optimizely/php-sdk?branch=master)
4+
[![Total Downloads](https://poser.pugx.org/optimizely/optimizely-sdk/downloads)](https://packagist.org/packages/optimizely/optimizely-sdk)
45
[![Apache 2.0](https://img.shields.io/github/license/nebula-plugins/gradle-extra-configurations-plugin.svg)](http://www.apache.org/licenses/LICENSE-2.0)
56

67
This repository houses the PHP SDK for Optimizely Full Stack.
@@ -9,7 +10,11 @@ This repository houses the PHP SDK for Optimizely Full Stack.
910

1011
###Installing the SDK
1112

12-
The Optimizely PHP SDK will be available through [Composer](https://getcomposer.org/). Instructions coming soon.
13+
The Optimizely PHP SDK can be installed through [Composer](https://getcomposer.org/). Please use the following command:
14+
15+
```
16+
php composer.phar require optimizely/optimizely-sdk
17+
```
1318

1419
###Using the SDK
1520
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.

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
},
1919
"require-dev": {
2020
"phpunit/phpunit": "~4.8|~5.0",
21-
"satooshi/php-coveralls": "dev-master"
21+
"satooshi/php-coveralls": "v1.0.1"
2222
},
2323
"autoload": {
2424
"psr-4": {

src/Optimizely/Event/Builder/EventBuilder.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class EventBuilder
3333
/**
3434
* @const string Version of the Optimizely PHP SDK.
3535
*/
36-
const SDK_VERSION = '0.1.0';
36+
const SDK_VERSION = '1.0.0';
3737

3838
/**
3939
* @var string URL to send impression event to.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/**
3+
* Copyright 2016, Optimizely
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
namespace Optimizely\Event\Dispatcher;
19+
20+
use Exception;
21+
use Optimizely\Event\LogEvent;
22+
23+
/**
24+
* Class CurlEventDispatcher
25+
*
26+
* @package Optimizely\Event\Dispatcher
27+
*/
28+
class CurlEventDispatcher implements EventDispatcherInterface
29+
{
30+
public function dispatchEvent(LogEvent $event)
31+
{
32+
$cmd = "curl";
33+
$cmd.= " -X ".$event->getHttpVerb();
34+
foreach($event->getHeaders() as $type => $value) {
35+
$cmd.= " -H '".$type.": ".$value."'";
36+
}
37+
$cmd.= " -d '".json_encode($event->getParams())."'";
38+
$cmd.= " '".$event->getUrl()."' > /dev/null 2>&1 &";
39+
exec($cmd, $output, $exit_code);
40+
41+
if ($exit_code !== 0) {
42+
throw new Exception('Curl command failed.');
43+
}
44+
}
45+
}

src/Optimizely/ProjectConfig.php

+5-5
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,11 @@ public function __construct($datafile, $logger, $errorHandler)
129129
$this->_projectId = $config['projectId'];
130130
$this->_revision = $config['revision'];
131131

132-
$groups = $config['groups'];
133-
$experiments = $config['experiments'];
134-
$events = $config['events'];
135-
$attributes = $config['attributes'];
136-
$audiences = $config['audiences'];
132+
$groups = $config['groups'] ?: [];
133+
$experiments = $config['experiments'] ?: [];
134+
$events = $config['events'] ?: [];
135+
$attributes = $config['attributes'] ?: [];
136+
$audiences = $config['audiences'] ?: [];
137137

138138
$this->_groupIdMap = ConfigParser::generateMap($groups, 'id', Group::class);
139139
$this->_experimentKeyMap = ConfigParser::generateMap($experiments, 'key', Experiment::class);

tests/EventTests/EventBuilderTest.php

+6-6
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public function testCreateImpressionEventNoAttributes()
4848
'layerId' => '7719770039',
4949
'visitorId' => 'testUserId',
5050
'clientEngine' => 'php-sdk',
51-
'clientVersion' => '0.1.0',
51+
'clientVersion' => '1.0.0',
5252
'timestamp' => time() * 1000,
5353
'isGlobalHoldback' => false,
5454
'userFeatures' => [],
@@ -82,7 +82,7 @@ public function testCreateImpressionEventWithAttributes()
8282
'layerId' => '7719770039',
8383
'visitorId' => 'testUserId',
8484
'clientEngine' => 'php-sdk',
85-
'clientVersion' => '0.1.0',
85+
'clientVersion' => '1.0.0',
8686
'timestamp' => time() * 1000,
8787
'isGlobalHoldback' => false,
8888
'userFeatures' => [[
@@ -126,7 +126,7 @@ public function testCreateConversionEventNoAttributesNoValue()
126126
'accountId' => '1592310167',
127127
'visitorId' => 'testUserId',
128128
'clientEngine' => 'php-sdk',
129-
'clientVersion' => '0.1.0',
129+
'clientVersion' => '1.0.0',
130130
'userFeatures' => [],
131131
'isGlobalHoldback' => false,
132132
'timestamp' => time() * 1000,
@@ -168,7 +168,7 @@ public function testCreateConversionEventWithAttributesNoValue()
168168
'accountId' => '1592310167',
169169
'visitorId' => 'testUserId',
170170
'clientEngine' => 'php-sdk',
171-
'clientVersion' => '0.1.0',
171+
'clientVersion' => '1.0.0',
172172
'isGlobalHoldback' => false,
173173
'timestamp' => time() * 1000,
174174
'eventFeatures' => [],
@@ -221,7 +221,7 @@ public function testCreateConversionEventNoAttributesWithValue()
221221
'accountId' => '1592310167',
222222
'visitorId' => 'testUserId',
223223
'clientEngine' => 'php-sdk',
224-
'clientVersion' => '0.1.0',
224+
'clientVersion' => '1.0.0',
225225
'userFeatures' => [],
226226
'isGlobalHoldback' => false,
227227
'timestamp' => time() * 1000,
@@ -266,7 +266,7 @@ public function testCreateConversionEventWithAttributesWithValue()
266266
'accountId' => '1592310167',
267267
'visitorId' => 'testUserId',
268268
'clientEngine' => 'php-sdk',
269-
'clientVersion' => '0.1.0',
269+
'clientVersion' => '1.0.0',
270270
'isGlobalHoldback' => false,
271271
'timestamp' => time() * 1000,
272272
'eventFeatures' => [],

tests/OptimizelyTest.php

+34-2
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,6 @@ public function testValidateInputsInvalidFileJsonValidationSkipped()
156156
$validateInputsMethod->invoke(new Optimizely('Random datafile', null, null, null, true),
157157
'Random datafile', true)
158158
);
159-
160-
$this->expectOutputRegex('/Provided "datafile" is in an invalid format./');
161159
}
162160

163161
public function testValidatePreconditionsExperimentNotRunning()
@@ -277,6 +275,40 @@ public function testActivateInvalidAttributes()
277275
$this->assertNull($optlyObject->activate('test_experiment', 'test_user', 42));
278276
}
279277

278+
public function testActivateUserInNoVariation()
279+
{
280+
$userAttributes = [
281+
'device_type' => 'iPhone',
282+
'company' => 'Optimizely',
283+
'location' => 'San Francisco'
284+
];
285+
286+
$this->eventBuilderMock->expects($this->never())
287+
->method('createImpressionEvent');
288+
289+
$this->loggerMock->expects($this->exactly(3))
290+
->method('log');
291+
$this->loggerMock->expects($this->at(0))
292+
->method('log')
293+
->with(Logger::DEBUG, 'Assigned bucket 8495 to user "not_in_variation_user".');
294+
$this->loggerMock->expects($this->at(1))
295+
->method('log')
296+
->with(Logger::INFO,
297+
'User "not_in_variation_user" is in no variation.');
298+
$this->loggerMock->expects($this->at(2))
299+
->method('log')
300+
->with(Logger::INFO, 'Not activating user "not_in_variation_user".');
301+
302+
$optlyObject = new Optimizely($this->datafile, new ValidEventDispatcher(), $this->loggerMock);
303+
304+
$eventBuilder = new \ReflectionProperty(Optimizely::class, '_eventBuilder');
305+
$eventBuilder->setAccessible(true);
306+
$eventBuilder->setValue($optlyObject, $this->eventBuilderMock);
307+
308+
// Call activate
309+
$this->assertNull($optlyObject->activate('test_experiment', 'not_in_variation_user', $userAttributes));
310+
}
311+
280312
public function testActivateNoAudienceNoAttributes()
281313
{
282314
$this->eventBuilderMock->expects($this->once())

tests/UtilsTests/ConditionEvaluatorTest.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class ConditionEvaluatorTest extends \PHPUnit_Framework_TestCase
2929
public function setUp()
3030
{
3131
$decoder = new ConditionDecoder();
32-
$conditions = "[\"and\", [\"or\", [\"or\", {\"name\": \"device_type\", \"type\": \"custom_attribute\", \"value\": \"iPhone\"}]], [\"or\", [\"or\", {\"name\": \"location\", \"type\": \"custom_attribute\", \"value\": \"San Francisco\"}]]]";
32+
$conditions = "[\"and\", [\"or\", [\"or\", {\"name\": \"device_type\", \"type\": \"custom_attribute\", \"value\": \"iPhone\"}]], [\"or\", [\"or\", {\"name\": \"location\", \"type\": \"custom_attribute\", \"value\": \"San Francisco\"}]], [\"or\", [\"not\", [\"or\", {\"name\": \"browser\", \"type\": \"custom_attribute\", \"value\": \"Firefox\"}]]]]";
3333
$decoder->deserializeAudienceConditions($conditions);
3434

3535
$this->conditionsList = $decoder->getConditionsList();
@@ -41,7 +41,7 @@ public function testEvaluateConditionsMatch()
4141
$userAttributes = [
4242
'device_type' => 'iPhone',
4343
'location' => 'San Francisco',
44-
'browser' => 'chrome'
44+
'browser' => 'Chrome'
4545
];
4646

4747
$this->assertTrue($this->conditionEvaluator->evaluate($this->conditionsList, $userAttributes));
@@ -51,8 +51,9 @@ public function testEvaluateConditionsMatch()
5151
public function testEvaluateConditionsDoNotMatch()
5252
{
5353
$userAttributes = [
54+
'device_type' => 'iPhone',
5455
'location' => 'San Francisco',
55-
'browser' => 'chrome'
56+
'browser' => 'Firefox'
5657
];
5758

5859
$this->assertFalse($this->conditionEvaluator->evaluate($this->conditionsList, $userAttributes));

0 commit comments

Comments
 (0)