diff options
Diffstat (limited to 'www/crm/wp-content/plugins/civicrm/civicrm/ext/api4/Civi/Api4/Generic/Traits/ArrayQueryActionTrait.php')
-rw-r--r-- | www/crm/wp-content/plugins/civicrm/civicrm/ext/api4/Civi/Api4/Generic/Traits/ArrayQueryActionTrait.php | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/www/crm/wp-content/plugins/civicrm/civicrm/ext/api4/Civi/Api4/Generic/Traits/ArrayQueryActionTrait.php b/www/crm/wp-content/plugins/civicrm/civicrm/ext/api4/Civi/Api4/Generic/Traits/ArrayQueryActionTrait.php new file mode 100644 index 00000000..1d223f1b --- /dev/null +++ b/www/crm/wp-content/plugins/civicrm/civicrm/ext/api4/Civi/Api4/Generic/Traits/ArrayQueryActionTrait.php @@ -0,0 +1,197 @@ +<?php + +namespace Civi\Api4\Generic\Traits; +use Civi\API\Exception\NotImplementedException; + +/** + * Helper functions for performing api queries on arrays of data. + * + * @package Civi\Api4\Generic + */ +trait ArrayQueryActionTrait { + + /** + * @param array $values + * List of all rows + * @return array + * Filtered list of rows + */ + protected function queryArray($values) { + $values = $this->filterArray($values); + $values = $this->sortArray($values); + $values = $this->selectArray($values); + $values = $this->limitArray($values); + return $values; + } + + /** + * @param array $values + * @return array + */ + protected function filterArray($values) { + if ($this->getWhere()) { + $values = array_filter($values, [$this, 'evaluateFilters']); + } + return array_values($values); + } + + /** + * @param array $row + * @return bool + */ + private function evaluateFilters($row) { + $where = $this->getWhere(); + $allConditions = in_array($where[0], ['AND', 'OR', 'NOT']) ? $where : ['AND', $where]; + return $this->walkFilters($row, $allConditions); + } + + /** + * @param array $row + * @param array $filters + * @return bool + * @throws \Civi\API\Exception\NotImplementedException + */ + private function walkFilters($row, $filters) { + switch ($filters[0]) { + case 'AND': + case 'NOT': + $result = TRUE; + foreach ($filters[1] as $filter) { + if (!$this->walkFilters($row, $filter)) { + $result = FALSE; + break; + } + } + return $result == ($filters[0] == 'AND'); + + case 'OR': + $result = !count($filters[1]); + foreach ($filters[1] as $filter) { + if ($this->walkFilters($row, $filter)) { + return TRUE; + } + } + return $result; + + default: + return $this->filterCompare($row, $filters); + } + } + + /** + * @param array $row + * @param array $condition + * @return bool + * @throws \Civi\API\Exception\NotImplementedException + */ + private function filterCompare($row, $condition) { + if (!is_array($condition)) { + throw new NotImplementedException('Unexpected where syntax; expecting array.'); + } + $value = isset($row[$condition[0]]) ? $row[$condition[0]] : NULL; + $operator = $condition[1]; + $expected = isset($condition[2]) ? $condition[2] : NULL; + switch ($operator) { + case '=': + case '!=': + case '<>': + $equal = $value == $expected; + // PHP is too imprecise about comparing the number 0 + if ($expected === 0 || $expected === '0') { + $equal = ($value === 0 || $value === '0'); + } + // PHP is too imprecise about comparing empty strings + if ($expected === '') { + $equal = ($value === ''); + } + return $equal == ($operator == '='); + + case 'IS NULL': + case 'IS NOT NULL': + return is_null($value) == ($operator == 'IS NULL'); + + case '>': + return $value > $expected; + + case '>=': + return $value >= $expected; + + case '<': + return $value < $expected; + + case '<=': + return $value <= $expected; + + case 'BETWEEN': + case 'NOT BETWEEN': + $between = ($value >= $expected[0] && $value <= $expected[1]); + return $between == ($operator == 'BETWEEN'); + + case 'LIKE': + case 'NOT LIKE': + $pattern = '/^' . str_replace('%', '.*', preg_quote($expected, '/')) . '$/i'; + return !preg_match($pattern, $value) == ($operator != 'LIKE'); + + case 'IN': + return in_array($value, $expected); + + case 'NOT IN': + return !in_array($value, $expected); + + default: + throw new NotImplementedException("Unsupported operator: '$operator' cannot be used with array data"); + } + } + + /** + * @param $values + * @return array + */ + protected function sortArray($values) { + if ($this->getOrderBy()) { + usort($values, [$this, 'sortCompare']); + } + return $values; + } + + private function sortCompare($a, $b) { + foreach ($this->getOrderBy() as $field => $dir) { + $modifier = $dir == 'ASC' ? 1 : -1; + if (isset($a[$field]) && isset($b[$field])) { + if ($a[$field] == $b[$field]) { + continue; + } + return (strnatcasecmp($a[$field], $b[$field]) * $modifier); + } + elseif (isset($a[$field]) || isset($b[$field])) { + return ((isset($a[$field]) ? 1 : -1) * $modifier); + } + } + return 0; + } + + /** + * @param $values + * @return array + */ + protected function selectArray($values) { + if ($this->getSelect()) { + foreach ($values as &$value) { + $value = array_intersect_key($value, array_flip($this->getSelect())); + } + } + return $values; + } + + /** + * @param $values + * @return array + */ + protected function limitArray($values) { + if ($this->getOffset() || $this->getLimit()) { + $values = array_slice($values, $this->getOffset() ?: 0, $this->getLimit() ?: NULL); + } + return $values; + } + +} |