*/
abstract class SqlFunction extends SqlExpression {
+ /**
+ * @var array
+ */
protected static $params = [];
+ /**
+ * @var array[]
+ */
protected $args = [];
/**
*/
protected function initialize() {
$arg = trim(substr($this->expr, strpos($this->expr, '(') + 1, -1));
- foreach ($this->getParams() as $param) {
+ foreach ($this->getParams() as $idx => $param) {
$prefix = $this->captureKeyword($param['prefix'], $arg);
+ $this->args[$idx] = [
+ 'prefix' => $prefix,
+ 'expr' => [],
+ 'suffix' => NULL,
+ ];
if ($param['expr'] && isset($prefix) || in_array('', $param['prefix']) || !$param['optional']) {
- $this->captureExpressions($arg, $param['expr'], $param['must_be'], $param['cant_be']);
- $this->captureKeyword($param['suffix'], $arg);
+ $this->args[$idx]['expr'] = $this->captureExpressions($arg, $param['expr'], $param['must_be'], $param['cant_be']);
+ $this->args[$idx]['suffix'] = $this->captureKeyword($param['suffix'], $arg);
}
}
}
/**
- * Shift a keyword off the beginning of the argument string and into the argument array.
+ * Shift a keyword off the beginning of the argument string and return it.
*
* @param array $keywords
* Whitelist of keywords
private function captureKeyword($keywords, &$arg) {
foreach (array_filter($keywords) as $key) {
if (strpos($arg, $key . ' ') === 0) {
- $this->args[] = $key;
$arg = ltrim(substr($arg, strlen($key)));
return $key;
}
}
/**
- * Shifts 0 or more expressions off the argument string and into the argument array
+ * Shifts 0 or more expressions off the argument string and returns them
*
* @param string $arg
* @param int $limit
* @param array $mustBe
* @param array $cantBe
+ * @return array
* @throws \API_Exception
*/
private function captureExpressions(&$arg, $limit, $mustBe, $cantBe) {
- $captured = 0;
+ $captured = [];
$arg = ltrim($arg);
while ($arg) {
$item = $this->captureExpression($arg);
$arg = ltrim(substr($arg, strlen($item)));
$expr = SqlExpression::convert($item, FALSE, $mustBe, $cantBe);
$this->fields = array_merge($this->fields, $expr->getFields());
- if ($captured) {
- $this->args[] = ',';
- }
- $this->args[] = $expr;
+ $captured[] = $expr;
$captured++;
// Keep going if we have a comma indicating another expression follows
- if ($captured < $limit && substr($arg, 0, 1) === ',') {
+ if (count($captured) < $limit && substr($arg, 0, 1) === ',') {
$arg = ltrim(substr($arg, 1));
}
else {
- return;
+ break;
}
}
+ return $captured;
}
/**
return $item;
}
+ /**
+ * Render the expression for insertion into the sql query
+ *
+ * @param array $fieldList
+ * @return string
+ */
public function render(array $fieldList): string {
- $output = $this->getName() . '(';
+ $output = '';
+ $params = $this->getParams();
foreach ($this->args as $index => $arg) {
- if ($index && $arg !== ',') {
- $output .= ' ';
- }
- if (is_object($arg)) {
- $output .= $arg->render($fieldList);
+ $rendered = $this->renderArg($arg, $params[$index], $fieldList);
+ if (strlen($rendered)) {
+ $output .= (strlen($output) ? ' ' : '') . $rendered;
}
- else {
- $output .= $arg;
+ }
+ return $this->getName() . '(' . $output . ')';
+ }
+
+ /**
+ * @param array $arg
+ * @param array $param
+ * @param array $fieldList
+ * @return string
+ */
+ private function renderArg($arg, $param, $fieldList): string {
+ // Supply api_default
+ if (!isset($arg['prefix']) && !isset($arg['suffix']) && empty($arg['expr']) && !empty($param['api_default'])) {
+ $arg = [
+ 'prefix' => $param['api_default']['prefix'] ?? reset($param['prefix']),
+ 'expr' => array_map([parent::class, 'convert'], $param['api_default']['expr'] ?? []),
+ 'suffix' => $param['api_default']['suffix'] ?? reset($param['suffix']),
+ ];
+ }
+ $rendered = $arg['prefix'] ?? '';
+ foreach ($arg['expr'] ?? [] as $idx => $expr) {
+ if (strlen($rendered) || $idx) {
+ $rendered .= $idx ? ', ' : ' ';
}
+ $rendered .= $expr->render($fieldList);
+ }
+ if (isset($arg['suffix'])) {
+ $rendered .= (strlen($rendered) ? ' ' : '') . $arg['suffix'];
}
- return $output . ')';
+ return $rendered;
}
/**
'optional' => FALSE,
'must_be' => [],
'cant_be' => ['SqlWild'],
+ 'api_default' => NULL,
];
}
return $params;
}
+ /**
+ * Get the arguments passed to this sql function instance.
+ * @return array[]
+ */
+ public function getArgs(): array {
+ return $this->args;
+ }
+
/**
* @return string
*/