/** * Parses the innards of the table definition block for info * @param string $aql * @param array $parent (if in a subquery) * @return array { fields, subqueries, objects, clauses } */ public function inner($aql, $parent = array()) { $tmp = array(); $subqueries = $this->split_tables($aql, true); $subqueries = $subqueries[0]; if (is_array($subqueries)) { $subs = array(); $sub = ''; foreach ($subqueries as $k => $v) { if (stripos(trim($v), "'") > 2 || stripos(trim($v), "'") === false) { // FOR MULTIPLE SUBQUERIES $aql = str_replace($v, '', $aql); if (!preg_match('/\\},$/', trim($v))) { $sub .= $v; } else { $sub .= $v; $sub = substr($sub, 0, -1); $subs[] = $sub; $sub = ''; } } } $subs[] = $sub; foreach ($subs as $s) { $sub = $this->init($s, $parent); if (!empty($sub)) { $keys = array_keys($sub); $tmp['subqueries'][$keys[0]] = $sub; } } } // remove opening brace and before and last brace and whitespace $aql = trim(substr(substr($aql, 0, -1), strpos($aql, '{') + 1)); // get clauses foreach (array_reverse(self::$clauses) as $cl) { $pattern = sprintf('/(?:\\b%s\\b)%s/i', $cl, "(?=(?:(?:[^']*+'){2})*+[^']*+\\z)"); $split = preg_split($pattern, $aql, 2); $aql = $split[0]; if ($split[1]) { $tmp[$cl] = $split[1]; } } preg_match_all(self::$object_pattern, $aql, $matches); $aql = str_replace($matches[0], '', $aql); foreach ($matches['model'] as $k => $v) { $primary_table = aql::get_primary_table($v); $constructor_arg = $matches['param'][$k] ?: $primary_table . '_id'; $object_tmp = array('model' => $v, 'primary_table' => $primary_table, 'constructor argument' => $constructor_arg); $tmp_as = $matches['as'][$k] ?: $v; if ($matches['sub'][$k]) { $object_tmp['plural'] = true; $object_tmp['sub_where'] = $this->subquery_where($primary_table, $primary_table, $parent['table'], $parent['as']); } $tmp['objects'][$tmp_as] = $object_tmp; } $i = 1; $fields = explodeOnComma($aql); array_walk($fields, function ($field, $_, $o) use($parent, &$tmp, &$i) { $add_field = function ($alias, $value, $type = 'fields') use(&$tmp) { $tmp[$type][$alias] = $value; }; $field = trim($field); if (empty($field)) { return; } if ($field == '*') { $fields = $o->get_table_fields($parent['table']); if (is_array($fields)) { foreach ($fields as $f) { $tmp['fields'][$f] = $parent['as'] . '.' . $f; } } return; } $as = array_map('trim', preg_split("/\\bas\\b{$o->not_in_quotes}/", $field)); $alias = $as[1] ?: $as[0]; if (strpos($alias, "'") !== false) { $alias = 'field_' . $i; } if (!$as[0] || !$alias) { return; } if (preg_match("/(case|when){$o->not_in_quotes}/im", $as[0])) { // this is a case when $add_field($alias, trim($o->parse_case_when($as[0], $parent['as']))); } else { if (strpos($as[0], ')') !== false) { // this is a "function" we call it an aggregate for now $a = array_map('trim', explode('(', $as[0])); if (!empty($a[0])) { $alias = $alias == $as[0] ? $a[0] : $alias; if ($tmp['aggregates'][$alias]) { $j = '1'; while (true) { if ($tmp['aggregates'][$alias . '_' . $j]) { $j++; continue; } $alias = $alias . '_' . $i; break; } } // end if alias is already taken. $add_field($alias, $o->aggregate_add_table_name($parent['as'], $as[0]), 'aggregates'); } else { $add_field($alias, $as[0]); } } else { // regular field $add_field($alias, trim($o->add_table_name($parent['as'], $as[0]))); } } $i++; }, $this); $tmp['fields'] = $tmp['fields'] ?: array(); $tmp['aggregates'] = $tmp['aggregates'] ?: array(); foreach (array('order by', 'group by') as $cl) { $tmp[$cl] = $this->check_clause(explodeOnComma($tmp[$cl]), $parent, array_merge($tmp['fields'], $tmp['aggregates'])); } $tmp['where'] = preg_split('/\\band\\b(?=(?:(?:(?:[^()]++|\\.)*+[()]){2})*+(?:[^())]++|\\.)*+$)/i', $tmp['where']); return $tmp; }
/** * Given the aql array, append table names to strings in the clause aray if they are * missing * @param array $aql_array * @param array $clause_array */ public static function check_clause_array($aql_array, $clause_array) { $first = reset($aql_array); $clauses = aql2array::$clauses; $comparisons = aql2array::$comparisons; foreach ($clause_array as $k => $v) { if (in_array($k, $clauses)) { $clause_array = array($first['as'] => $clause_array); break; } } foreach ($clause_array as $table => $v) { if (!is_array($v)) { continue; } foreach ($v as $clause => $value) { if ($clause == 'where') { $value = is_array($value) ? $value : array($value); $arr = aql2array::prepare_where($value, $aql_array[$table]['table']); $clause_array[$table][$clause] = aql2array::check_where($arr, $aql_array[$table]['as']); } else { $value = is_array($value) ? $value : explodeOnComma($value); $clause_array[$table][$clause] = aql2array::check_clause($value, $aql_array[$table], $aql_array[$table]['fields']); } } } return $clause_array; }