APIv4 - Add support for sql equations
[civicrm-core.git] / Civi / Api4 / Query / SqlEquation.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 namespace Civi\Api4\Query;
13
14 /**
15 * Numeric sql expression
16 */
17 class SqlEquation extends SqlExpression {
18
19 /**
20 * @var array
21 */
22 protected $args = [];
23
24 /**
25 * @var string[]
26 */
27 public static $arithmeticOperators = [
28 '+',
29 '-',
30 '*',
31 '/',
32 ];
33
34 /**
35 * @var string[]
36 */
37 public static $comparisonOperators = [
38 '<=',
39 '>=',
40 '<',
41 '>',
42 '=',
43 '!=',
44 '<=>',
45 'IS NOT',
46 'IS',
47 'BETWEEN',
48 'AND',
49 ];
50
51 protected function initialize() {
52 $arg = trim(substr($this->expr, strpos($this->expr, '(') + 1, -1));
53 $permitted = ['SqlField', 'SqlString', 'SqlNumber', 'SqlNull'];
54 $operators = array_merge(self::$arithmeticOperators, self::$comparisonOperators);
55 while (strlen($arg)) {
56 $this->args = array_merge($this->args, $this->captureExpressions($arg, $permitted, FALSE));
57 $op = $this->captureKeyword($operators, $arg);
58 if ($op) {
59 $this->args[] = $op;
60 }
61 }
62 }
63
64 /**
65 * Render the expression for insertion into the sql query
66 *
67 * @param array $fieldList
68 * @return string
69 */
70 public function render(array $fieldList): string {
71 $output = [];
72 foreach ($this->args as $arg) {
73 $output[] = is_string($arg) ? $arg : $arg->render($fieldList);
74 }
75 return '(' . implode(' ', $output) . ')';
76 }
77
78 /**
79 * Returns the alias to use for SELECT AS.
80 *
81 * @return string
82 */
83 public function getAlias(): string {
84 return $this->alias ?? \CRM_Utils_String::munge(trim($this->expr, ' ()'), '_', 256);
85 }
86
87 /**
88 * Change $dataType according to operator used in equation
89 *
90 * @see \Civi\Api4\Utils\FormattingUtil::formatOutputValues
91 * @param string $value
92 * @param string $dataType
93 * @return string
94 */
95 public function formatOutputValue($value, &$dataType) {
96 foreach (self::$comparisonOperators as $op) {
97 if (strpos($this->expr, " $op ")) {
98 $dataType = 'Boolean';
99 }
100 }
101 foreach (self::$arithmeticOperators as $op) {
102 if (strpos($this->expr, " $op ")) {
103 $dataType = 'Float';
104 }
105 }
106 return $value;
107 }
108
109 }