16
16
*/
17
17
namespace Optimizely ;
18
18
19
+ use Doctrine \Instantiator \Exception \InvalidArgumentException ;
19
20
use Exception ;
20
- use Optimizely \Entity \ Experiment ;
21
+ use Optimizely \Exceptions \ InvalidAttributeException ;
21
22
use Throwable ;
23
+ use Monolog \Logger ;
24
+ use Optimizely \Entity \Experiment ;
25
+ use Optimizely \Logger \DefaultLogger ;
22
26
use Optimizely \ErrorHandler \ErrorHandlerInterface ;
23
27
use Optimizely \ErrorHandler \NoOpErrorHandler ;
24
28
use Optimizely \Event \Builder \EventBuilder ;
@@ -65,6 +69,11 @@ class Optimizely
65
69
*/
66
70
private $ _eventBuilder ;
67
71
72
+ /**
73
+ * @var boolean Denotes whether Optimizely object is valid or not.
74
+ */
75
+ private $ _isValid ;
76
+
68
77
/**
69
78
* Optimizely constructor for managing Full Stack PHP projects.
70
79
*
@@ -80,17 +89,35 @@ public function __construct($datafile,
80
89
ErrorHandlerInterface $ errorHandler = null ,
81
90
$ skipJsonValidation = false )
82
91
{
92
+ $ this ->_isValid = true ;
83
93
$ this ->_eventDispatcher = $ eventDispatcher ?: new DefaultEventDispatcher ();
84
- $ this ->_logger = $ logger ?: new NoOpLogger ();;
85
- $ this ->_errorHandler = $ errorHandler ?: new NoOpErrorHandler ();;
94
+ $ this ->_logger = $ logger ?: new NoOpLogger ();
95
+ $ this ->_errorHandler = $ errorHandler ?: new NoOpErrorHandler ();
96
+
97
+ if (!$ this ->validateInputs ($ datafile , $ skipJsonValidation )) {
98
+ $ this ->_isValid = false ;
99
+ $ this ->_logger = new DefaultLogger ();
100
+ $ this ->_logger ->log (Logger::ERROR , 'Provided "datafile" has invalid schema. ' );
101
+ return ;
102
+ }
86
103
87
- $ this ->validateInputs ($ datafile , $ skipJsonValidation );
88
104
try {
89
- $ this ->_config = new ProjectConfig ($ datafile );
105
+ $ this ->_config = new ProjectConfig ($ datafile, $ this -> _logger , $ this -> _errorHandler );
90
106
}
91
- catch (Throwable $ exception ) {}
92
- catch (Exception $ exception ) {}
93
- $ this ->_bucketer = new Bucketer ();
107
+ catch (Throwable $ exception ) {
108
+ $ this ->_isValid = false ;
109
+ $ this ->_logger = new DefaultLogger ();
110
+ $ this ->_logger ->log (Logger::ERROR , 'Provided "datafile" is in an invalid format. ' );
111
+ return ;
112
+ }
113
+ catch (Exception $ exception ) {
114
+ $ this ->_isValid = false ;
115
+ $ this ->_logger = new DefaultLogger ();
116
+ $ this ->_logger ->log (Logger::ERROR , 'Provided "datafile" is in an invalid format. ' );
117
+ return ;
118
+ }
119
+
120
+ $ this ->_bucketer = new Bucketer ($ this ->_logger );
94
121
$ this ->_eventBuilder = new EventBuilder ($ this ->_bucketer );
95
122
}
96
123
@@ -119,9 +146,16 @@ private function validateInputs($datafile, $skipJsonValidation)
119
146
*/
120
147
private function validatePreconditions ($ experiment , $ userId , $ attributes )
121
148
{
122
- //@TODO(ali): Insert attributes validation
149
+ if (!is_null ($ attributes ) && !Validator::areAttributesValid ($ attributes )) {
150
+ $ this ->_logger ->log (Logger::ERROR , 'Provided attributes are in an invalid format. ' );
151
+ $ this ->_errorHandler ->handleError (
152
+ new InvalidAttributeException ('Provided attributes are in an invalid format. ' )
153
+ );
154
+ return false ;
155
+ }
123
156
124
157
if (!$ experiment ->isExperimentRunning ()) {
158
+ $ this ->_logger ->log (Logger::INFO , sprintf ('Experiment "%s" is not running. ' , $ experiment ->getKey ()));
125
159
return false ;
126
160
}
127
161
@@ -130,6 +164,10 @@ private function validatePreconditions($experiment, $userId, $attributes)
130
164
}
131
165
132
166
if (!Validator::isUserInExperiment ($ this ->_config , $ experiment , $ attributes )) {
167
+ $ this ->_logger ->log (
168
+ Logger::INFO ,
169
+ sprintf ('User "%s" does not meet conditions to be in experiment "%s". ' , $ userId , $ experiment ->getKey ())
170
+ );
133
171
return false ;
134
172
}
135
173
@@ -147,27 +185,52 @@ private function validatePreconditions($experiment, $userId, $attributes)
147
185
*/
148
186
public function activate ($ experimentKey , $ userId , $ attributes = null )
149
187
{
188
+ if (!$ this ->_isValid ) {
189
+ $ this ->_logger ->log (Logger::ERROR , 'Datafile has invalid format. Failing "activate". ' );
190
+ return null ;
191
+ }
192
+
150
193
$ experiment = $ this ->_config ->getExperimentFromKey ($ experimentKey );
151
194
152
195
if (is_null ($ experiment ->getKey ())) {
196
+ $ this ->_logger ->log (Logger::INFO , sprintf ('Not activating user "%s". ' , $ userId ));
153
197
return null ;
154
198
}
155
199
156
200
if (!$ this ->validatePreconditions ($ experiment , $ userId , $ attributes )) {
201
+ $ this ->_logger ->log (Logger::INFO , sprintf ('Not activating user "%s". ' , $ userId ));
157
202
return null ;
158
203
}
159
204
160
205
$ variation = $ this ->_bucketer ->bucket ($ this ->_config , $ experiment , $ userId );
161
206
$ variationKey = $ variation ->getKey ();
162
207
163
208
if (is_null ($ variationKey )) {
209
+ $ this ->_logger ->log (Logger::INFO , sprintf ('Not activating user "%s". ' , $ userId ));
164
210
return $ variationKey ;
165
211
}
166
212
167
213
$ impressionEvent = $ this ->_eventBuilder
168
214
->createImpressionEvent ($ this ->_config , $ experiment , $ variation ->getId (), $ userId , $ attributes );
215
+ $ this ->_logger ->log (Logger::INFO , sprintf ('Activating user "%s" in experiment "%s". ' , $ userId , $ experimentKey ));
216
+ $ this ->_logger ->log (
217
+ Logger::DEBUG ,
218
+ sprintf ('Dispatching impression event to URL %s with params %s. ' ,
219
+ $ impressionEvent ->getUrl (), implode (', ' , $ impressionEvent ->getParams ())
220
+ )
221
+ );
169
222
170
- $ this ->_eventDispatcher ->dispatchEvent ($ impressionEvent );
223
+ try {
224
+ $ this ->_eventDispatcher ->dispatchEvent ($ impressionEvent );
225
+ }
226
+ catch (Throwable $ exception ) {
227
+ $ this ->_logger ->log (Logger::ERROR , sprintf (
228
+ 'Unable to dispatch impression event. Error %s ' , $ exception ->getMessage ()));
229
+ }
230
+ catch (Exception $ exception ) {
231
+ $ this ->_logger ->log (Logger::ERROR , sprintf (
232
+ 'Unable to dispatch impression event. Error %s ' , $ exception ->getMessage ()));
233
+ }
171
234
172
235
return $ variationKey ;
173
236
}
@@ -182,13 +245,23 @@ public function activate($experimentKey, $userId, $attributes = null)
182
245
*/
183
246
public function track ($ eventKey , $ userId , $ attributes = null , $ eventValue = null )
184
247
{
248
+ if (!$ this ->_isValid ) {
249
+ $ this ->_logger ->log (Logger::ERROR , 'Datafile has invalid format. Failing "track". ' );
250
+ return ;
251
+ }
252
+
185
253
if (!is_null ($ attributes ) && !Validator::areAttributesValid ($ attributes )) {
254
+ $ this ->_logger ->log (Logger::ERROR , 'Provided attributes are in an invalid format. ' );
255
+ $ this ->_errorHandler ->handleError (
256
+ new InvalidAttributeException ('Provided attributes are in an invalid format. ' )
257
+ );
186
258
return ;
187
259
}
188
260
189
261
$ event = $ this ->_config ->getEvent ($ eventKey );
190
262
191
263
if (is_null ($ event ->getKey ())) {
264
+ $ this ->_logger ->log (Logger::ERROR , sprintf ('Not tracking user "%s" for event "%s". ' , $ userId , $ eventKey ));
192
265
return ;
193
266
}
194
267
@@ -198,6 +271,9 @@ public function track($eventKey, $userId, $attributes = null, $eventValue = null
198
271
$ experiment = $ this ->_config ->getExperimentFromId ($ experimentId );
199
272
if ($ this ->validatePreconditions ($ experiment , $ userId , $ attributes )) {
200
273
array_push ($ validExperiments , $ experiment );
274
+ } else {
275
+ $ this ->_logger ->log (Logger::INFO , sprintf ('Not tracking user "%s" for experiment "%s". ' ,
276
+ $ userId , $ experiment ->getKey ()));
201
277
}
202
278
}
203
279
@@ -211,7 +287,30 @@ public function track($eventKey, $userId, $attributes = null, $eventValue = null
211
287
$ attributes ,
212
288
$ eventValue
213
289
);
214
- $ this ->_eventDispatcher ->dispatchEvent ($ conversionEvent );
290
+ $ this ->_logger ->log (Logger::INFO , sprintf ('Tracking event "%s" for user "%s". ' , $ eventKey , $ userId ));
291
+ $ this ->_logger ->log (
292
+ Logger::DEBUG ,
293
+ sprintf ('Dispatching conversion event to URL %s with params %s. ' ,
294
+ $ conversionEvent ->getUrl (), implode (', ' , $ conversionEvent ->getParams ())
295
+ ));
296
+
297
+ try {
298
+ $ this ->_eventDispatcher ->dispatchEvent ($ conversionEvent );
299
+ }
300
+ catch (Throwable $ exception ) {
301
+ $ this ->_logger ->log (Logger::ERROR , sprintf (
302
+ 'Unable to dispatch conversion event. Error %s ' , $ exception ->getMessage ()));
303
+ }
304
+ catch (Exception $ exception ) {
305
+ $ this ->_logger ->log (Logger::ERROR , sprintf (
306
+ 'Unable to dispatch conversion event. Error %s ' , $ exception ->getMessage ()));
307
+ }
308
+
309
+ } else {
310
+ $ this ->_logger ->log (
311
+ Logger::INFO ,
312
+ sprintf ('There are no valid experiments for event "%s" to track. ' , $ eventKey )
313
+ );
215
314
}
216
315
}
217
316
@@ -226,6 +325,11 @@ public function track($eventKey, $userId, $attributes = null, $eventValue = null
226
325
*/
227
326
public function getVariation ($ experimentKey , $ userId , $ attributes = null )
228
327
{
328
+ if (!$ this ->_isValid ) {
329
+ $ this ->_logger ->log (Logger::ERROR , 'Datafile has invalid format. Failing "getVariation". ' );
330
+ return null ;
331
+ }
332
+
229
333
$ experiment = $ this ->_config ->getExperimentFromKey ($ experimentKey );
230
334
231
335
if (is_null ($ experiment ->getKey ())) {
0 commit comments