name = $name ?: null; $query->type = strtoupper($attribs['action'] ?? '') ?: 'SELECT'; $query->alias = $attribs['alias'] ?? null; if ($query->alias && !$query->name) { $query->name = $query->alias; } // Load attributes that only apply to subqueries in the block. $query->operation = $attribs['operation'] ?? null; $query->column = preg_replace('/[^a-z0-9_\.]/i', '', $attribs['column'] ?? '') ?: null; $query->pipe = strtoupper($attribs['pipe'] ?? '') ?: 'AND'; // Load tables. foreach ($xml->tables ? $xml->tables->children() : [] as $tag) { if (trim($tag['query'] ?? '') === 'true') { $table = self::_parseQuery($tag); $table_type = 'subquery'; $query->tables[$table->alias] = $table; } else { $table = new DBQuery\Table; $table->name = trim($tag['name']); $table->alias = trim($tag['alias'] ?? '') ?: null; $table->ifvar = trim($tag['if'] ?? '') ?: null; $table_type = 'default'; } $join_type = trim($tag['type'] ?? ''); if ($table_type !== 'subquery' && stripos($join_type, 'join') !== false) { $table->join_type = strtoupper($join_type); if ($tag->conditions) { $table->join_conditions = self::_parseConditions($tag->conditions); } } $query->tables[$table->alias ?: $table->name] = $table; } // Load index hints. foreach ($xml->index_hint ?: [] as $index_hint_group) { $index_hint_target_db = strtolower(trim($index_hint_group['for'] ?? '')); if ($index_hint_target_db !== '' && $index_hint_target_db !== 'all') { $index_hint_target_db = explode(',', $index_hint_target_db); $index_hint_target_db = array_combine($index_hint_target_db, array_fill(0, count($index_hint_target_db), true)); } else { $index_hint_target_db = []; } foreach ($index_hint_group->children() ?: [] as $tag) { $index_hint = new DBQuery\IndexHint; $index_hint->target_db = $index_hint_target_db; $index_hint->hint_type = strtoupper(trim($tag['type'] ?? '')) ?: 'USE'; $index_hint->index_name = trim($tag['name'] ?? '') ?: ''; $index_hint->table_name = trim($tag['table'] ?? '') ?: ''; $index_hint->ifvar = trim($tag['if'] ?? '') ?: null; if (isset($tag['var']) && trim($tag['var'] ?? '')) { $index_hint->var = trim($tag['var'] ?? ''); } if (isset($tag['default']) && trim($tag['default'] ?? '')) { $index_hint->index_name = trim($tag['default'] ?? ''); } if ($index_hint->index_name || $index_hint->var) { $query->index_hints[] = $index_hint; } } } // Load columns. foreach ($xml->columns ? $xml->columns->children() : [] as $tag) { if ($tag->getName() === 'query') { $subquery = self::_parseQuery($tag, trim($tag['id'] ?? '')); $query->columns[] = $subquery; } elseif ($query->type === 'SELECT') { $column = new DBQuery\ColumnRead; $column->name = trim($tag['name']); $column->alias = trim($tag['alias'] ?? '') ?: null; $column->ifvar = trim($tag['if'] ?? '') ?: null; if ($column->name === '*' || preg_match('/\.\*$/', $column->name)) { $column->is_wildcard = true; } if (!DBQuery\Query::isValidColumnName($column->name)) { $column->is_expression = true; } $query->columns[] = $column; } else { $attribs = self::_getAttributes($tag); $column = new DBQuery\ColumnWrite; $column->name = $attribs['name']; $column->operation = ($attribs['operation'] ?? null) ?: 'equal'; $column->var = $attribs['var'] ?? null; $column->ifvar = $attribs['if'] ?? null; $column->default = $attribs['default'] ?? null; $column->not_null = ($attribs['notnull'] ?? false) ? true : false; $column->filter = $attribs['filter'] ?? null; $column->minlength = intval($attribs['minlength'] ?? 0, 10); $column->maxlength = intval($attribs['maxlength'] ?? 0, 10); $query->columns[] = $column; } } // Load conditions. if ($xml->conditions) { $query->conditions = self::_parseConditions($xml->conditions); } // Load groups. if ($xml->groups) { $query->groupby = new DBQuery\GroupBy; $query->groupby->ifvar = trim($xml->groups['if'] ?? '') ?: null; foreach ($xml->groups->children() as $tag) { $name = $tag->getName(); $ifvar = trim($tag['if'] ?? '') ?: null; if ($name === 'group') { $query->groupby->columns[] = [trim($tag['column'] ?? ''), $ifvar]; } elseif ($name === 'having') { $query->groupby->having = self::_parseConditions($tag); } } } // Load navigation settings. if ($xml->navigation) { $query->navigation = new DBQuery\Navigation; foreach ($xml->navigation->index ?: [] as $tag) { $attribs = self::_getAttributes($tag, true); $orderby = new DBQuery\OrderBy; $orderby->var = ($attribs['var'] ?? null) ?: null; $orderby->default = ($attribs['default'] ?? null) ?: null; $orderby->order_var = ($attribs['order'] ?? null) ?: null; $orderby->order_default = strtoupper($attribs['orderdefault'] ?? '') === 'DESC' ? 'DESC' : 'ASC'; $orderby->ifvar = trim($attribs['if'] ?? '') ?: null; $query->navigation->orderby[] = $orderby; } foreach (['list_count', 'page_count', 'page', 'offset'] as $key) { if ($tag = $xml->navigation->{$key}) { $query->navigation->{$key} = new DBQuery\VariableBase; $query->navigation->{$key}->var = trim($tag['var'] ?? '') ?: null; $query->navigation->{$key}->default = trim($tag['default'] ?? '') ?: null; $query->navigation->{$key}->ifvar = trim($tag['if'] ?? '') ?: null; } } } // If a SELECT query has no columns, use * by default. if ($query->type === 'SELECT' && !count($query->columns)) { $column = new DBQuery\ColumnRead; $column->name = '*'; $column->is_wildcard = true; $column->is_expression = true; $query->columns[] = $column; } // Check the SELECT DISTINCT flag. if ($xml->columns && $select_distinct = trim($xml->columns['distinct'] ?? '')) { if ($select_distinct === 'distinct' || toBool($select_distinct)) { $query->select_distinct = true; } } // Check the ON DUPLICATE KEY UPDATE (upsert) flag. if ($query->type === 'INSERT' && $update_duplicate = self::_getAttributes($xml)['updateduplicate'] ?? false) { if (toBool($update_duplicate)) { $query->update_duplicate = true; } } // Return the complete query definition. return $query; } /** * Parse conditions. * * @param \SimpleXMLElement $parent * @return array */ protected static function _parseConditions(\SimpleXMLElement $parent): array { $result = array(); foreach ($parent->children() as $tag) { $attribs = self::_getAttributes($tag); $name = $tag->getName(); if ($name === 'condition') { $cond = new DBQuery\Condition; $cond->operation = $attribs['operation']; $cond->column = $attribs['column']; if (isset($attribs['var']) && !isset($attribs['default']) && preg_match('/^\w+\.\w+$/', $attribs['var'])) { $cond->default = $attribs['var']; } else { $cond->var = $attribs['var'] ?? null; $cond->default = $attribs['default'] ?? null; } $cond->ifvar = $attribs['if'] ?? null; $cond->not_null = ($attribs['notnull'] ?? false) ? true : false; $cond->filter = $attribs['filter'] ?? null; $cond->minlength = intval($attribs['minlength'] ?? 0, 10); $cond->maxlength = intval($attribs['maxlength'] ?? 0, 10); $cond->pipe = strtoupper($attribs['pipe'] ?? '') ?: 'AND'; $result[] = $cond; } elseif ($name === 'group') { $group = new DBQuery\ConditionGroup; $group->conditions = self::_parseConditions($tag); $group->pipe = strtoupper($attribs['pipe'] ?? '') ?: 'AND'; $group->ifvar = $attribs['if'] ?? null; $group->not_null = ($attribs['notnull'] ?? false) ? true : false; $result[] = $group; } elseif ($name === 'query') { $subquery = self::_parseQuery($tag); $subquery->ifvar = $attribs['if'] ?? null; $result[] = $subquery; } } return $result; } }