$condition Condition config. * @param array $context Workflow context. * @return bool */ abstract public function evaluate( array $condition, array $context ): bool; /** * Compare two values with a named operator. * * @param string $operator Operator method name (equals, contains, ...). * @param mixed $variable Left-hand value. * @param mixed $value Right-hand value. * @return bool */ public function compare( string $operator, $variable, $value ): bool { $operator = trim( $operator ); if ( '' === $operator || ! method_exists( $this, $operator ) ) { return false; } return (bool) $this->{$operator}( $variable, $value ); } /** * Evaluate "equals" operator. * * @param mixed $variable * @param mixed $value * @return bool */ protected function equals($variable, $value): bool { if (is_numeric($variable) && is_numeric($value)) { return (float)$variable === (float)$value; } return (string)$variable === (string)$value; } /** * Evaluate "not_equals" operator. * * @param mixed $variable * @param mixed $value * @return bool */ protected function not_equals($variable, $value): bool { if (is_numeric($variable) && is_numeric($value)) { return (float)$variable != (float)$value; } return (string)$variable != (string)$value; } /** * Evaluate "less_than" operator. * * @param mixed $variable * @param mixed $value * @return bool */ protected function less_than($variable, $value): bool { if (is_numeric($variable) && is_numeric($value)) { return (float)$variable < (float)$value; } return false; } /** * Evaluate "greater_than" operator. * * @param mixed $variable * @param mixed $value * @return bool */ protected function greater_than($variable, $value): bool { if (is_numeric($variable) && is_numeric($value)) { return (float)$variable > (float)$value; } return false; } /** * Evaluate "less_than_or_equal" operator. * * @param mixed $variable * @param mixed $value * @return bool */ protected function less_than_or_equal($variable, $value): bool { if (is_numeric($variable) && is_numeric($value)) { return (float)$variable <= (float)$value; } return false; } /** * Evaluate "greater_than_or_equal" operator. * * @param mixed $variable * @param mixed $value * @return bool */ protected function greater_than_or_equal($variable, $value): bool { if (is_numeric($variable) && is_numeric($value)) { return (float)$variable >= (float)$value; } return false; } /** * Evaluate "between" operator. * * @param mixed $variable * @param mixed $value * @return bool */ protected function between($variable, $value): bool { $valueArray = null; try { $valueArray = @json_decode($value, true) ?? null; if (is_array($valueArray) && count($valueArray) === 2) { [$min, $max] = $valueArray; return $variable >= $min && $variable <= $max; } // must decode to array, so we return false return false; } catch (\Exception $e) { // decoding failed, so we treat the value as not an array return false; } } /** * Evaluate "not_between" operator. * * @param mixed $variable * @param mixed $value * @return bool */ protected function not_between($variable, $value): bool { $valueArray = null; try { $valueArray = @json_decode($value, true) ?? null; if (is_array($valueArray) && count($valueArray) === 2) { [$min, $max] = $valueArray; return $variable < $min || $variable > $max; } // must decode to array, so we return false return false; } catch (\Exception $e) { // decoding failed, so we treat the value as not an array return false; } } /** * Evaluate "in" operator. * * @param mixed $variable * @param mixed $value * @return bool */ protected function in($variable, $value): bool { // Handle both JSON-encoded array and PHP array string without quotes (e.g., [apples, bananas, oranges]) $valueArray = null; try { $valueArray = @json_decode($value, true) ?? null; if (!is_array($valueArray)) { // Try to handle a string like [apples, bananas, oranges] (values unquoted, single string) $trimmed = trim($value); if (preg_match('/^\[\s*([^\]]*)\s*\]$/', $trimmed, $matches)) { $content = $matches[1]; // Split by comma and trim values $valueArray = array_map('trim', explode(',', $content)); } } if (is_array($valueArray)) { return in_array($variable, $valueArray); } // must decode to array, so we return false return false; } catch (\Exception $e) { // decoding failed, so we treat the value as not an array return false; } } /** * Evaluate "not_in" operator. * * @param mixed $variable * @param mixed $value * @return bool */ protected function not_in($variable, $value): bool { $valueArray = null; try { $valueArray = @json_decode($value, true) ?? null; if (!is_array($valueArray)) { // Try to handle a string like [apples, bananas, oranges] (values unquoted, single string) $trimmed = trim($value); if (preg_match('/^\[\s*([^\]]*)\s*\]$/', $trimmed, $matches)) { $content = $matches[1]; // Split by comma and trim values $valueArray = array_map('trim', explode(',', $content)); } } if (!is_array($valueArray)) { // must decode to array, so we return false return false; } return !in_array($variable, $valueArray); } catch (\Exception $e) { // decoding failed, so we treat the value as not an array return false; } } /** * Evaluate "contains" operator. * * @param mixed $variable * @param mixed $value * @return bool */ protected function contains($variable, $value): bool { $valueArray = null; try { $valueArray = @json_decode($value, true) ?? null; if (!is_array($valueArray)) { // Try to handle a string like [apples, bananas, oranges] (values unquoted, single string) $trimmed = trim($value); if (preg_match('/^\[\s*([^\]]*)\s*\]$/', $trimmed, $matches)) { $content = $matches[1]; // Split by comma and trim values $valueArray = array_map('trim', explode(',', $content)); } } } catch (\Exception $e) {} if (is_array($valueArray)) { return in_array($variable, $valueArray); } if (is_string($value)) { return mb_strpos($value, (string)$variable) !== false; } return false; } }