public function doesConditionMatch(HeraldEngine $engine, HeraldRule $rule, HeraldCondition $condition, $field_value) { $condition_type = $condition->getFieldCondition(); $condition_value = $condition->getValue(); switch ($condition_type) { case self::CONDITION_CONTAINS: // "Contains" can take an array of strings, as in "Any changed // filename" for diffs. foreach ((array) $field_value as $value) { if (stripos($value, $condition_value) !== false) { return true; } } return false; case self::CONDITION_NOT_CONTAINS: return stripos($field_value, $condition_value) === false; case self::CONDITION_IS: return $field_value == $condition_value; case self::CONDITION_IS_NOT: return $field_value != $condition_value; case self::CONDITION_IS_ME: return $field_value == $rule->getAuthorPHID(); case self::CONDITION_IS_NOT_ME: return $field_value != $rule->getAuthorPHID(); case self::CONDITION_IS_ANY: if (!is_array($condition_value)) { throw new HeraldInvalidConditionException(pht('Expected condition value to be an array.')); } $condition_value = array_fuse($condition_value); return isset($condition_value[$field_value]); case self::CONDITION_IS_NOT_ANY: if (!is_array($condition_value)) { throw new HeraldInvalidConditionException(pht('Expected condition value to be an array.')); } $condition_value = array_fuse($condition_value); return !isset($condition_value[$field_value]); case self::CONDITION_INCLUDE_ALL: if (!is_array($field_value)) { throw new HeraldInvalidConditionException(pht('Object produced non-array value!')); } if (!is_array($condition_value)) { throw new HeraldInvalidConditionException(pht('Expected condition value to be an array.')); } $have = array_select_keys(array_fuse($field_value), $condition_value); return count($have) == count($condition_value); case self::CONDITION_INCLUDE_ANY: return (bool) array_select_keys(array_fuse($field_value), $condition_value); case self::CONDITION_INCLUDE_NONE: return !array_select_keys(array_fuse($field_value), $condition_value); case self::CONDITION_EXISTS: case self::CONDITION_IS_TRUE: return (bool) $field_value; case self::CONDITION_NOT_EXISTS: case self::CONDITION_IS_FALSE: return !$field_value; case self::CONDITION_UNCONDITIONALLY: return (bool) $field_value; case self::CONDITION_NEVER: return false; case self::CONDITION_REGEXP: foreach ((array) $field_value as $value) { // We add the 'S' flag because we use the regexp multiple times. // It shouldn't cause any troubles if the flag is already there // - /.*/S is evaluated same as /.*/SS. $result = @preg_match($condition_value . 'S', $value); if ($result === false) { throw new HeraldInvalidConditionException(pht('Regular expression is not valid!')); } if ($result) { return true; } } return false; case self::CONDITION_REGEXP_PAIR: // Match a JSON-encoded pair of regular expressions against a // dictionary. The first regexp must match the dictionary key, and the // second regexp must match the dictionary value. If any key/value pair // in the dictionary matches both regexps, the condition is satisfied. $regexp_pair = null; try { $regexp_pair = phutil_json_decode($condition_value); } catch (PhutilJSONParserException $ex) { throw new HeraldInvalidConditionException(pht('Regular expression pair is not valid JSON!')); } if (count($regexp_pair) != 2) { throw new HeraldInvalidConditionException(pht('Regular expression pair is not a pair!')); } $key_regexp = array_shift($regexp_pair); $value_regexp = array_shift($regexp_pair); foreach ((array) $field_value as $key => $value) { $key_matches = @preg_match($key_regexp, $key); if ($key_matches === false) { throw new HeraldInvalidConditionException(pht('First regular expression is invalid!')); } if ($key_matches) { $value_matches = @preg_match($value_regexp, $value); if ($value_matches === false) { throw new HeraldInvalidConditionException(pht('Second regular expression is invalid!')); } if ($value_matches) { return true; } } } return false; case self::CONDITION_RULE: case self::CONDITION_NOT_RULE: $rule = $engine->getRule($condition_value); if (!$rule) { throw new HeraldInvalidConditionException(pht('Condition references a rule which does not exist!')); } $is_not = $condition_type == self::CONDITION_NOT_RULE; $result = $engine->doesRuleMatch($rule, $this); if ($is_not) { $result = !$result; } return $result; case self::CONDITION_HAS_BIT: return ($condition_value & $field_value) === (int) $condition_value; case self::CONDITION_NOT_BIT: return ($condition_value & $field_value) !== (int) $condition_value; default: throw new HeraldInvalidConditionException(pht("Unknown condition '%s'.", $condition_type)); } }