1616 */
1717namespace Optimizely ;
1818
19+ use Doctrine \Instantiator \Exception \InvalidArgumentException ;
1920use Exception ;
20- use Optimizely \Entity \ Experiment ;
21+ use Optimizely \Exceptions \ InvalidAttributeException ;
2122use Throwable ;
23+ use Monolog \Logger ;
24+ use Optimizely \Entity \Experiment ;
25+ use Optimizely \Logger \DefaultLogger ;
2226use Optimizely \ErrorHandler \ErrorHandlerInterface ;
2327use Optimizely \ErrorHandler \NoOpErrorHandler ;
2428use Optimizely \Event \Builder \EventBuilder ;
@@ -65,6 +69,11 @@ class Optimizely
6569 */
6670 private $ _eventBuilder ;
6771
72+ /**
73+ * @var boolean Denotes whether Optimizely object is valid or not.
74+ */
75+ private $ _isValid ;
76+
6877 /**
6978 * Optimizely constructor for managing Full Stack PHP projects.
7079 *
@@ -80,17 +89,35 @@ public function __construct($datafile,
8089 ErrorHandlerInterface $ errorHandler = null ,
8190 $ skipJsonValidation = false )
8291 {
92+ $ this ->_isValid = true ;
8393 $ 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+ }
86103
87- $ this ->validateInputs ($ datafile , $ skipJsonValidation );
88104 try {
89- $ this ->_config = new ProjectConfig ($ datafile );
105+ $ this ->_config = new ProjectConfig ($ datafile, $ this -> _logger , $ this -> _errorHandler );
90106 }
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 );
94121 $ this ->_eventBuilder = new EventBuilder ($ this ->_bucketer );
95122 }
96123
@@ -119,9 +146,16 @@ private function validateInputs($datafile, $skipJsonValidation)
119146 */
120147 private function validatePreconditions ($ experiment , $ userId , $ attributes )
121148 {
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+ }
123156
124157 if (!$ experiment ->isExperimentRunning ()) {
158+ $ this ->_logger ->log (Logger::INFO , sprintf ('Experiment "%s" is not running. ' , $ experiment ->getKey ()));
125159 return false ;
126160 }
127161
@@ -130,6 +164,10 @@ private function validatePreconditions($experiment, $userId, $attributes)
130164 }
131165
132166 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+ );
133171 return false ;
134172 }
135173
@@ -147,27 +185,52 @@ private function validatePreconditions($experiment, $userId, $attributes)
147185 */
148186 public function activate ($ experimentKey , $ userId , $ attributes = null )
149187 {
188+ if (!$ this ->_isValid ) {
189+ $ this ->_logger ->log (Logger::ERROR , 'Datafile has invalid format. Failing "activate". ' );
190+ return null ;
191+ }
192+
150193 $ experiment = $ this ->_config ->getExperimentFromKey ($ experimentKey );
151194
152195 if (is_null ($ experiment ->getKey ())) {
196+ $ this ->_logger ->log (Logger::INFO , sprintf ('Not activating user "%s". ' , $ userId ));
153197 return null ;
154198 }
155199
156200 if (!$ this ->validatePreconditions ($ experiment , $ userId , $ attributes )) {
201+ $ this ->_logger ->log (Logger::INFO , sprintf ('Not activating user "%s". ' , $ userId ));
157202 return null ;
158203 }
159204
160205 $ variation = $ this ->_bucketer ->bucket ($ this ->_config , $ experiment , $ userId );
161206 $ variationKey = $ variation ->getKey ();
162207
163208 if (is_null ($ variationKey )) {
209+ $ this ->_logger ->log (Logger::INFO , sprintf ('Not activating user "%s". ' , $ userId ));
164210 return $ variationKey ;
165211 }
166212
167213 $ impressionEvent = $ this ->_eventBuilder
168214 ->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+ );
169222
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+ }
171234
172235 return $ variationKey ;
173236 }
@@ -182,13 +245,23 @@ public function activate($experimentKey, $userId, $attributes = null)
182245 */
183246 public function track ($ eventKey , $ userId , $ attributes = null , $ eventValue = null )
184247 {
248+ if (!$ this ->_isValid ) {
249+ $ this ->_logger ->log (Logger::ERROR , 'Datafile has invalid format. Failing "track". ' );
250+ return ;
251+ }
252+
185253 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+ );
186258 return ;
187259 }
188260
189261 $ event = $ this ->_config ->getEvent ($ eventKey );
190262
191263 if (is_null ($ event ->getKey ())) {
264+ $ this ->_logger ->log (Logger::ERROR , sprintf ('Not tracking user "%s" for event "%s". ' , $ userId , $ eventKey ));
192265 return ;
193266 }
194267
@@ -198,6 +271,9 @@ public function track($eventKey, $userId, $attributes = null, $eventValue = null
198271 $ experiment = $ this ->_config ->getExperimentFromId ($ experimentId );
199272 if ($ this ->validatePreconditions ($ experiment , $ userId , $ attributes )) {
200273 array_push ($ validExperiments , $ experiment );
274+ } else {
275+ $ this ->_logger ->log (Logger::INFO , sprintf ('Not tracking user "%s" for experiment "%s". ' ,
276+ $ userId , $ experiment ->getKey ()));
201277 }
202278 }
203279
@@ -211,7 +287,30 @@ public function track($eventKey, $userId, $attributes = null, $eventValue = null
211287 $ attributes ,
212288 $ eventValue
213289 );
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+ );
215314 }
216315 }
217316
@@ -226,6 +325,11 @@ public function track($eventKey, $userId, $attributes = null, $eventValue = null
226325 */
227326 public function getVariation ($ experimentKey , $ userId , $ attributes = null )
228327 {
328+ if (!$ this ->_isValid ) {
329+ $ this ->_logger ->log (Logger::ERROR , 'Datafile has invalid format. Failing "getVariation". ' );
330+ return null ;
331+ }
332+
229333 $ experiment = $ this ->_config ->getExperimentFromKey ($ experimentKey );
230334
231335 if (is_null ($ experiment ->getKey ())) {
0 commit comments