protected function getQueryNativeField(DatabaseQuerySelect $query, $selector, $fields)
{
$value = $selector->value;
$values = is_array($value) ? $value : array($value);
$SQL = '';
$database = $this->wire('database');
foreach ($fields as $field) {
// the following fields are defined in each iteration here because they may be modified in the loop
$table = "pages";
$operator = $selector->operator;
$subfield = '';
$IDs = array();
// populated in special cases where we can just match parent IDs
$sql = '';
if (strpos($field, '.')) {
list($field, $subfield) = explode('.', $field);
}
if (!$this->wire('fields')->isNative($field)) {
$subfield = $field;
$field = 'children';
}
if ($field == 'child') {
$field = 'children';
}
if (in_array($field, array('parent', 'parent_id', 'children'))) {
if (strpos($field, 'parent') === 0 && (!$subfield || in_array($subfield, array('id', 'path', 'url')))) {
// match by location (id or path)
// convert parent fields like '/about/company/history' to the equivalent ID
foreach ($values as $k => $v) {
if (ctype_digit("{$v}")) {
continue;
}
$v = $this->wire('sanitizer')->pagePathName($v);
if (strpos($v, '/') === false) {
$v = "/{$v}";
}
// prevent a plain string with no slashes
// convert path to id
$parent = $this->wire('pages')->get($v);
if (!$parent instanceof NullPage) {
$values[$k] = $parent->id;
} else {
$values[$k] = null;
}
}
$field = 'parent_id';
if (count($values) == 1 && $selector->getOperator() === '=') {
$this->parent_id = reset($values);
}
} else {
// matching by a parent's native or custom field (subfield)
if (!$this->wire('fields')->isNative($subfield)) {
$finder = new PageFinder();
$s = $field == 'children' ? '' : 'children.count>0, ';
$IDs = $finder->findIDs(new Selectors("include=all, {$s}{$subfield}{$operator}" . implode('|', $values)));
if (!count($IDs)) {
$IDs[] = -1;
}
// forced non match
} else {
// native
static $n = 0;
if ($field == 'children') {
$table = "_children_native" . ++$n;
$query->join("pages AS {$table} ON {$table}.parent_id=pages.id");
} else {
$table = "_parent_native" . ++$n;
$query->join("pages AS {$table} ON pages.parent_id={$table}.id");
}
$field = $subfield;
}
}
}
if (count($IDs)) {
// parentIDs are IDs found via another query, and we don't need to match anything other than the parent ID
$in = $selector->not ? "NOT IN" : "IN";
$sql .= in_array($field, array('parent', 'parent_id')) ? "{$table}.parent_id " : "{$table}.id ";
$sql .= "{$in}(" . implode(',', $IDs) . ")";
} else {
foreach ($values as $value) {
if (is_null($value)) {
// an invalid/unknown walue was specified, so make sure it fails
$sql .= "1>2";
continue;
}
if (in_array($field, array('templates_id', 'template'))) {
// convert templates specified as a name to the numeric template ID
// allows selectors like 'template=my_template_name'
$field = 'templates_id';
if (count($values) == 1 && $selector->getOperator() === '=') {
$this->templates_id = reset($values);
}
if (!ctype_digit("{$value}")) {
$value = ($template = $this->fuel('templates')->get($value)) ? $template->id : 0;
}
}
if (in_array($field, array('created', 'modified', 'published'))) {
// prepare value for created, modified or published date fields
if (!ctype_digit($value)) {
$value = strtotime($value);
}
$value = date('Y-m-d H:i:s', $value);
}
if (in_array($field, array('id', 'parent_id', 'templates_id'))) {
$value = (int) $value;
}
$isName = $field === 'name' || strpos($field, 'name') === 0;
if ($isName && $operator == '~=') {
// handle one or more space-separated full words match to 'name' field in any order
$s = '';
foreach (explode(' ', $value) as $word) {
$word = $database->escapeStr($this->wire('sanitizer')->pageName($word));
$s .= ($s ? ' AND ' : '') . "{$table}.{$field} RLIKE '" . '[[:<:]]' . $word . '[[:>:]]' . "'";
}
} else {
if ($isName && in_array($operator, array('%=', '^=', '$=', '%^=', '%$=', '*='))) {
// handle partial match to 'name' field
$value = $database->escapeStr($this->wire('sanitizer')->pageName($value));
if ($operator == '^=' || $operator == '%^=') {
$value = "{$value}%";
} else {
if ($operator == '$=' || $operator == '%$=') {
$value = "%{$value}";
} else {
$value = "%{$value}%";
}
}
$s = "{$table}.{$field} LIKE '{$value}'";
} else {
if (!$database->isOperator($operator)) {
throw new PageFinderSyntaxException("Operator '{$operator}' is not supported for '{$field}'.");
} else {
if ($isName) {
$value = $this->wire('sanitizer')->pageName($value);
}
$value = $database->escapeStr($value);
$s = "{$table}." . $field . $operator . (ctype_digit("{$value}") && $field != 'name' ? (int) $value : "'{$value}'");
}
}
}
if ($selector->not) {
$s = "NOT ({$s})";
}
if ($operator == '!=' || $selector->not) {
$sql .= $sql ? " AND {$s}" : "{$s}";
} else {
$sql .= $sql ? " OR {$s}" : "{$s}";
}
}
}
if ($sql) {
if ($SQL) {
$SQL .= " OR ({$sql})";
} else {
$SQL .= "({$sql})";
}
}
}
if (count($fields) > 1) {
$SQL = "({$SQL})";
}
$query->where($SQL);
//$this->nativeWheres[] = $SQL;
}