1717
1818namespace Optimizely \Utils ;
1919
20+ use Monolog \Logger ;
21+ use Optimizely \Enums \AudienceEvaluationLogs as logs ;
2022use Optimizely \Utils \Validator ;
2123
2224class CustomAttributeConditionEvaluator
@@ -31,17 +33,19 @@ class CustomAttributeConditionEvaluator
3133
3234 /**
3335 * @var UserAttributes
34- */
36+ */
3537 protected $ userAttributes ;
3638
3739 /**
3840 * CustomAttributeConditionEvaluator constructor
3941 *
4042 * @param array $userAttributes Associative array of user attributes to values.
43+ * @param $logger LoggerInterface.
4144 */
42- public function __construct (array $ userAttributes )
45+ public function __construct (array $ userAttributes, $ logger )
4346 {
4447 $ this ->userAttributes = $ userAttributes ;
48+ $ this ->logger = $ logger ;
4549 }
4650
4751 /**
@@ -73,7 +77,7 @@ protected function getMatchTypes()
7377 /**
7478 * Gets the evaluator method name for the given match type.
7579 *
76- * @param string $matchType Match type for which to get evaluator.
80+ * @param string $matchType Match type for which to get evaluator.
7781 *
7882 * @return string Corresponding evaluator method name.
7983 */
@@ -92,13 +96,13 @@ protected function getEvaluatorByMatchType($matchType)
9296 /**
9397 * Checks if the given input is a valid value for exact condition evaluation.
9498 *
95- * @param $value Input to check.
99+ * @param $value Input to check.
96100 *
97- * @return boolean true if given input is a string/boolean/finite number, false otherwise.
101+ * @return boolean true if given input is a string/boolean/number, false otherwise.
98102 */
99- protected function isValueValidForExactConditions ($ value )
103+ protected function isValueTypeValidForExactConditions ($ value )
100104 {
101- if (is_string ($ value ) || is_bool ($ value ) || Validator:: isFiniteNumber ($ value )) {
105+ if (is_string ($ value ) || is_bool ($ value ) || is_int ( $ value ) || is_float ($ value )) {
102106 return true ;
103107 }
104108
@@ -108,7 +112,7 @@ protected function isValueValidForExactConditions($value)
108112 /**
109113 * Evaluate the given exact match condition for the given user attributes.
110114 *
111- * @param object $condition
115+ * @param object $condition
112116 *
113117 * @return null|boolean true if the user attribute value is equal (===) to the condition value,
114118 * false if the user attribute value is not equal (!==) to the condition value,
@@ -122,11 +126,34 @@ protected function exactEvaluator($condition)
122126 $ conditionValue = $ condition ['value ' ];
123127 $ userValue = isset ($ this ->userAttributes [$ conditionName ]) ? $ this ->userAttributes [$ conditionName ]: null ;
124128
125- if (!$ this ->isValueValidForExactConditions ($ userValue )
126- || !$ this ->isValueValidForExactConditions ($ conditionValue )
127- || !Validator::areValuesSameType ($ conditionValue , $ userValue )
128- ) {
129- return null ;
129+ if (!$ this ->isValueTypeValidForExactConditions ($ conditionValue ) ||
130+ ((is_int ($ conditionValue ) || is_float ($ conditionValue )) && !Validator::isFiniteNumber ($ conditionValue ))) {
131+ $ this ->logger ->log (Logger::WARNING , sprintf (
132+ logs::UNKNOWN_CONDITION_VALUE ,
133+ json_encode ($ condition )
134+ ));
135+ return null ;
136+ }
137+
138+ if (!$ this ->isValueTypeValidForExactConditions ($ userValue ) ||
139+ !Validator::areValuesSameType ($ conditionValue , $ userValue )) {
140+ $ this ->logger ->log (Logger::WARNING , sprintf (
141+ logs::UNEXPECTED_TYPE ,
142+ json_encode ($ condition ),
143+ gettype ($ userValue ),
144+ $ conditionName
145+ ));
146+ return null ;
147+ }
148+
149+ if ((is_int ($ userValue ) || is_float ($ userValue )) &&
150+ !Validator::isFiniteNumber ($ userValue )) {
151+ $ this ->logger ->log (Logger::WARNING , sprintf (
152+ logs::INFINITE_ATTRIBUTE_VALUE ,
153+ json_encode ($ condition ),
154+ $ conditionName
155+ ));
156+ return null ;
130157 }
131158
132159 return $ conditionValue == $ userValue ;
@@ -135,7 +162,7 @@ protected function exactEvaluator($condition)
135162 /**
136163 * Evaluate the given exists match condition for the given user attributes.
137164 *
138- * @param object $condition
165+ * @param object $condition
139166 *
140167 * @return null|boolean true if both:
141168 * 1) the user attributes have a value for the given condition, and
@@ -151,7 +178,7 @@ protected function existsEvaluator($condition)
151178 /**
152179 * Evaluate the given greater than match condition for the given user attributes.
153180 *
154- * @param object $condition
181+ * @param object $condition
155182 *
156183 * @return boolean true if the user attribute value is greater than the condition value,
157184 * false if the user attribute value is less than or equal to the condition value,
@@ -164,7 +191,30 @@ protected function greaterThanEvaluator($condition)
164191 $ conditionValue = $ condition ['value ' ];
165192 $ userValue = isset ($ this ->userAttributes [$ conditionName ]) ? $ this ->userAttributes [$ conditionName ]: null ;
166193
167- if (!Validator::isFiniteNumber ($ userValue ) || !Validator::isFiniteNumber ($ conditionValue )) {
194+ if (!Validator::isFiniteNumber ($ conditionValue )) {
195+ $ this ->logger ->log (Logger::WARNING , sprintf (
196+ logs::UNKNOWN_CONDITION_VALUE ,
197+ json_encode ($ condition )
198+ ));
199+ return null ;
200+ }
201+
202+ if (!(is_int ($ userValue ) || is_float ($ userValue ))) {
203+ $ this ->logger ->log (Logger::WARNING , sprintf (
204+ logs::UNEXPECTED_TYPE ,
205+ json_encode ($ condition ),
206+ gettype ($ userValue ),
207+ $ conditionName
208+ ));
209+ return null ;
210+ }
211+
212+ if (!Validator::isFiniteNumber ($ userValue )) {
213+ $ this ->logger ->log (Logger::WARNING , sprintf (
214+ logs::INFINITE_ATTRIBUTE_VALUE ,
215+ json_encode ($ condition ),
216+ $ conditionName
217+ ));
168218 return null ;
169219 }
170220
@@ -174,7 +224,7 @@ protected function greaterThanEvaluator($condition)
174224 /**
175225 * Evaluate the given less than match condition for the given user attributes.
176226 *
177- * @param object $condition
227+ * @param object $condition
178228 *
179229 * @return boolean true if the user attribute value is less than the condition value,
180230 * false if the user attribute value is greater than or equal to the condition value,
@@ -187,30 +237,67 @@ protected function lessThanEvaluator($condition)
187237 $ conditionValue = $ condition ['value ' ];
188238 $ userValue = isset ($ this ->userAttributes [$ conditionName ]) ? $ this ->userAttributes [$ conditionName ]: null ;
189239
190- if (!Validator::isFiniteNumber ($ userValue ) || !Validator::isFiniteNumber ($ conditionValue )) {
240+ if (!Validator::isFiniteNumber ($ conditionValue )) {
241+ $ this ->logger ->log (Logger::WARNING , sprintf (
242+ logs::UNKNOWN_CONDITION_VALUE ,
243+ json_encode ($ condition )
244+ ));
245+ return null ;
246+ }
247+
248+ if (!(is_int ($ userValue ) || is_float ($ userValue ))) {
249+ $ this ->logger ->log (Logger::WARNING , sprintf (
250+ logs::UNEXPECTED_TYPE ,
251+ json_encode ($ condition ),
252+ gettype ($ userValue ),
253+ $ conditionName
254+ ));
255+ return null ;
256+ }
257+
258+ if (!Validator::isFiniteNumber ($ userValue )) {
259+ $ this ->logger ->log (Logger::WARNING , sprintf (
260+ logs::INFINITE_ATTRIBUTE_VALUE ,
261+ json_encode ($ condition ),
262+ $ conditionName
263+ ));
191264 return null ;
192265 }
193266
194267 return $ userValue < $ conditionValue ;
195268 }
196269
197270 /**
198- * Evaluate the given substring than match condition for the given user attributes.
199- *
200- * @param object $condition
201- *
202- * @return boolean true if the condition value is a substring of the user attribute value,
203- * false if the condition value is not a substring of the user attribute value,
204- * null if the condition value isn't a string or the user attribute value
205- * isn't a string.
206- */
271+ * Evaluate the given substring than match condition for the given user attributes.
272+ *
273+ * @param object $condition
274+ *
275+ * @return boolean true if the condition value is a substring of the user attribute value,
276+ * false if the condition value is not a substring of the user attribute value,
277+ * null if the condition value isn't a string or the user attribute value
278+ * isn't a string.
279+ */
207280 protected function substringEvaluator ($ condition )
208281 {
209282 $ conditionName = $ condition ['name ' ];
210283 $ conditionValue = $ condition ['value ' ];
211284 $ userValue = isset ($ this ->userAttributes [$ conditionName ]) ? $ this ->userAttributes [$ conditionName ]: null ;
212285
213- if (!is_string ($ userValue ) || !is_string ($ conditionValue )) {
286+ if (!is_string ($ conditionValue )) {
287+ $ this ->logger ->log (Logger::WARNING , sprintf (
288+ logs::UNKNOWN_CONDITION_VALUE ,
289+ json_encode ($ condition )
290+ ));
291+ return null ;
292+ }
293+
294+ if (!is_string ($ userValue )) {
295+ $ this ->logger ->log (Logger::WARNING , sprintf (
296+ logs::UNEXPECTED_TYPE ,
297+ json_encode ($ condition ),
298+ gettype ($ userValue ),
299+ $ conditionName
300+ ));
214301 return null ;
215302 }
216303
@@ -220,7 +307,7 @@ protected function substringEvaluator($condition)
220307 /**
221308 * Function to evaluate audience conditions against user's attributes.
222309 *
223- * @param array $leafCondition Condition to be evaluated.
310+ * @param array $leafCondition Condition to be evaluated.
224311 *
225312 * @return null|boolean true/false if the given user attributes match/don't match the given conditions,
226313 * null if the given user attributes and conditions can't be evaluated.
@@ -230,6 +317,10 @@ public function evaluate($leafCondition)
230317 $ leafCondition = $ this ->setNullForMissingKeys ($ leafCondition );
231318
232319 if ($ leafCondition ['type ' ] !== self ::CUSTOM_ATTRIBUTE_CONDITION_TYPE ) {
320+ $ this ->logger ->log (Logger::WARNING , sprintf (
321+ logs::UNKNOWN_CONDITION_TYPE ,
322+ json_encode ($ leafCondition )
323+ ));
233324 return null ;
234325 }
235326
@@ -240,9 +331,35 @@ public function evaluate($leafCondition)
240331 }
241332
242333 if (!in_array ($ conditionMatch , $ this ->getMatchTypes ())) {
334+ $ this ->logger ->log (Logger::WARNING , sprintf (
335+ logs::UNKNOWN_MATCH_TYPE ,
336+ json_encode ($ leafCondition )
337+ ));
243338 return null ;
244339 }
245340
341+ $ conditionName = $ leafCondition ['name ' ];
342+
343+ if ($ leafCondition ['match ' ] !== self ::EXISTS_MATCH_TYPE ) {
344+ if (!array_key_exists ($ conditionName , $ this ->userAttributes )) {
345+ $ this ->logger ->log (Logger::DEBUG , sprintf (
346+ logs::MISSING_ATTRIBUTE_VALUE ,
347+ json_encode ($ leafCondition ),
348+ $ conditionName
349+ ));
350+ return null ;
351+ }
352+
353+ if (!isset ($ this ->userAttributes [$ conditionName ])) {
354+ $ this ->logger ->log (Logger::DEBUG , sprintf (
355+ logs::NULL_ATTRIBUTE_VALUE ,
356+ json_encode ($ leafCondition ),
357+ $ conditionName
358+ ));
359+ return null ;
360+ }
361+ }
362+
246363 $ evaluatorForMatch = $ this ->getEvaluatorByMatchType ($ conditionMatch );
247364 return $ this ->$ evaluatorForMatch ($ leafCondition );
248365 }
0 commit comments