Skip to content

Commit 6ad64e2

Browse files
1.5.0 (#77)
* Feature - IP Anonymization (#64) * :pen2: IP Anonymization var and getter in ProjectConfig.php :pen2: Added ip param in Event/Builder/EventBuilder.php :pen2: Changes to TestData.php :pen2: Changes in EventBuilderTest.php * ✏️ Modifed var/method name * Fixed bucketing ID tests. (#66) * Cherry-picked notification listeners and IP anonymization features for 1.5.0 release. * 📝 sendImpressionEvent and TestData update (#80) * Make listener public (#79) * Updated the Changelog for 1.5.0 release. (#78) * Updated the Changelog for 1.5.0 release. * Added more description to the CHANGELOG. * Bumped release version to 1.5.0 * Changed the hard-coded test client_version reference to refer to the const defined in the EventBuilder class. * Bumped the test file to 1.5.0. * Bumped version for the event builder test. * Bumped event builder test client version number. * More client version bump.
1 parent 9729c2c commit 6ad64e2

15 files changed

+2034
-443
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 1.5.0
2+
- Added support for notification listeners.
3+
- Added support for IP anonymization.
4+
15
## 1.4.0
26
- Added support for Numeric Metrics.
37
- Switched to new event API.

src/Optimizely/Event/Builder/EventBuilder.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class EventBuilder
3636
/**
3737
* @const string Version of the Optimizely PHP SDK.
3838
*/
39-
const SDK_VERSION = '1.4.0';
39+
const SDK_VERSION = '1.5.0';
4040

4141
/**
4242
* @var string URL to send event to.
@@ -76,7 +76,8 @@ private function getCommonParams($config, $userId, $attributes)
7676
VISITORS => [$visitor],
7777
REVISION => $config->getRevision(),
7878
CLIENT_ENGINE => self::SDK_TYPE,
79-
CLIENT_VERSION => self::SDK_VERSION
79+
CLIENT_VERSION => self::SDK_VERSION,
80+
ANONYMIZE_IP => $config->getAnonymizeIP()
8081
];
8182

8283
if(is_null($attributes))

src/Optimizely/Event/Builder/Params.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,5 @@
3636
define('KEY', 'key');
3737
define('TYPE', 'type');
3838
define('VALUE', 'value');
39-
define('UUID', 'uuid');
39+
define('UUID', 'uuid');
40+
define('ANONYMIZE_IP', 'anonymize_ip');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
/**
3+
* Copyright 2017, 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\Exceptions;
19+
20+
21+
class InvalidCallbackArgumentCountException extends OptimizelyException
22+
{
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
/**
3+
* Copyright 2017, 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\Exceptions;
19+
20+
21+
class InvalidNotificationTypeException extends OptimizelyException
22+
{
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
<?php
2+
/**
3+
* Copyright 2017, Optimizely Inc and Contributors
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+
namespace Optimizely\Notification;
18+
19+
use ArgumentCountError;
20+
use Exception;
21+
use Throwable;
22+
23+
use Monolog\Logger;
24+
25+
use Optimizely\ErrorHandler\ErrorHandlerInterface;
26+
use Optimizely\Exceptions\InvalidCallbackArgumentCountException;
27+
use Optimizely\Exceptions\InvalidNotificationTypeException;
28+
use Optimizely\Logger\LoggerInterface;
29+
use Optimizely\Logger\NoOpLogger;
30+
31+
class NotificationCenter
32+
{
33+
private $_notificationId;
34+
35+
private $_notifications;
36+
37+
private $_logger;
38+
39+
private $_errorHandler;
40+
41+
public function __construct(LoggerInterface $logger, ErrorHandlerInterface $errorHandler)
42+
{
43+
$this->_notificationId = 1;
44+
$this->_notifications = [];
45+
foreach (array_values(NotificationType::getAll()) as $type) {
46+
$this->_notifications[$type] = [];
47+
}
48+
49+
$this->_logger = $logger;
50+
$this->_errorHandler = $errorHandler;
51+
}
52+
53+
public function getNotifications()
54+
{
55+
return $this->_notifications;
56+
}
57+
58+
/**
59+
* Adds a notification callback for a notification type to the notification center
60+
* @param string $notification_type One of the constants defined in NotificationType
61+
* @param string $notification_callback A valid PHP callback
62+
*
63+
* @return null Given invalid notification type/callback
64+
* -1 Given callback has been already added
65+
* int Notification ID for the added callback
66+
*/
67+
public function addNotificationListener($notification_type, $notification_callback)
68+
{
69+
if (!NotificationType::isNotificationTypeValid($notification_type)) {
70+
$this->_logger->log(Logger::ERROR, "Invalid notification type.");
71+
$this->_errorHandler->handleError(new InvalidNotificationTypeException('Invalid notification type.'));
72+
return null;
73+
}
74+
75+
if (!is_callable($notification_callback)) {
76+
$this->_logger->log(Logger::ERROR, "Invalid notification callback.");
77+
return null;
78+
}
79+
80+
foreach (array_values($this->_notifications[$notification_type]) as $callback) {
81+
if ($notification_callback == $callback) {
82+
// Note: anonymous methods sent with the same body will be re-added.
83+
// Only variable and object methods can be checked for duplication
84+
$this->_logger->log(Logger::DEBUG, "Callback already added for notification type '{$notification_type}'.");
85+
return -1;
86+
}
87+
}
88+
89+
$this->_notifications[$notification_type][$this->_notificationId] = $notification_callback;
90+
$this->_logger->log(Logger::INFO, "Callback added for notification type '{$notification_type}'.");
91+
$returnVal = $this->_notificationId++;
92+
return $returnVal;
93+
}
94+
95+
/**
96+
* Removes notification callback from the notification center
97+
* @param int $notification_id notification IT
98+
*
99+
* @return true When callback removed
100+
* false When no callback found for the given notification ID
101+
*/
102+
public function removeNotificationListener($notification_id)
103+
{
104+
foreach ($this->_notifications as $notification_type => $notifications) {
105+
foreach (array_keys($notifications) as $id) {
106+
if ($notification_id == $id) {
107+
unset($this->_notifications[$notification_type][$id]);
108+
$this->_logger->log(Logger::INFO, "Callback with notification ID '{$notification_id}' has been removed.");
109+
return true;
110+
}
111+
}
112+
}
113+
114+
$this->_logger->log(Logger::DEBUG, "No Callback found with notification ID '{$notification_id}'.");
115+
return false;
116+
}
117+
118+
/**
119+
* Removes all notification callbacks for the given notification type
120+
* @param string $notification_type One of the constants defined in NotificationType
121+
*
122+
*/
123+
public function clearNotifications($notification_type)
124+
{
125+
if (!NotificationType::isNotificationTypeValid($notification_type)) {
126+
$this->_logger->log(Logger::ERROR, "Invalid notification type.");
127+
$this->_errorHandler->handleError(new InvalidNotificationTypeException('Invalid notification type.'));
128+
return;
129+
}
130+
131+
$this->_notifications[$notification_type] = [];
132+
$this->_logger->log(Logger::INFO, "All callbacks for notification type '{$notification_type}' have been removed.");
133+
}
134+
135+
/**
136+
* Removes all notifications for all notification types
137+
* from the notification center
138+
*
139+
*/
140+
public function cleanAllNotifications()
141+
{
142+
foreach (array_values(NotificationType::getAll()) as $type) {
143+
$this->_notifications[$type] = [];
144+
}
145+
}
146+
147+
/**
148+
* Executes all registered callbacks for the given notification type
149+
* @param [type] $notification_type One of the constants defined in NotificationType
150+
* @param array $args Array of items to pass as arguments to the callback
151+
*
152+
*/
153+
public function sendNotifications($notification_type, array $args = [])
154+
{
155+
if (!isset($this->_notifications[$notification_type])) {
156+
// No exception thrown and error logged since this method will be called from
157+
// within the SDK
158+
return;
159+
}
160+
161+
/**
162+
* Note: Before PHP 7, if the callback in call_user_func is called with less number of arguments than expected,
163+
* a warning is issued but the method is still executed with assigning null to the remaining
164+
* arguments. From PHP 7, ArgumentCountError is thrown in such case and the method isn't executed.
165+
* Therefore, we set error handler for warnings so that we raise an exception and notify the
166+
* user that the registered callback has more number of arguments than
167+
* expected. This should be done to keep a consistent behavior across all PHP versions.
168+
*/
169+
170+
set_error_handler(array($this, 'reportArgumentCountError'), E_WARNING);
171+
172+
foreach (array_values($this->_notifications[$notification_type]) as $callback) {
173+
try {
174+
call_user_func_array($callback, $args);
175+
} catch (ArgumentCountError $e) {
176+
$this->reportArgumentCountError();
177+
} catch (Exception $e) {
178+
$this->_logger->log(Logger::ERROR, "Problem calling notify callback.");
179+
}
180+
}
181+
182+
restore_error_handler();
183+
}
184+
185+
/**
186+
* Logs and raises an exception when registered callback expects more number of arguments when executed
187+
*
188+
*/
189+
public function reportArgumentCountError()
190+
{
191+
$this->_logger->log(Logger::ERROR, "Problem calling notify callback.");
192+
$this->_errorHandler->handleError(
193+
new InvalidCallbackArgumentCountException('Registered callback expects more number of arguments than the actual number')
194+
);
195+
}
196+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
/**
3+
* Copyright 2017, Optimizely Inc and Contributors
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+
namespace Optimizely\Notification;
18+
19+
class NotificationType
20+
{
21+
// format is EVENT: list of parameters to callback.
22+
const ACTIVATE = "ACTIVATE:experiment, user_id, attributes, variation, event";
23+
const TRACK = "TRACK:event_key, user_id, attributes, event_tags, event";
24+
25+
public static function isNotificationTypeValid($notification_type)
26+
{
27+
$oClass = new \ReflectionClass(__CLASS__);
28+
$notificationTypeList = array_values($oClass->getConstants());
29+
30+
return in_array($notification_type, $notificationTypeList);
31+
}
32+
33+
public static function getAll()
34+
{
35+
$oClass = new \ReflectionClass(__CLASS__);
36+
return $oClass->getConstants();
37+
}
38+
}

0 commit comments

Comments
 (0)