protected function postProcessQuery($parentQuery)
 {
     if (count($this->extraOrSelectors)) {
         // there were embedded OR selectors where one of them must match
         // i.e. id>0, field=(selector string), field=(selector string)
         // in the above example at least one 'field' must match
         // the 'field' portion is used only as a group name and isn't
         // actually used as part of the resulting query or than to know
         // what groups should be OR'd together
         $sqls = array();
         foreach ($this->extraOrSelectors as $groupName => $selectorGroup) {
             $n = 0;
             $sql = "\tpages.id IN (\n";
             foreach ($selectorGroup as $selectors) {
                 $pageFinder = new PageFinder();
                 $query = $pageFinder->find($selectors, array('returnQuery' => true, 'returnVerbose' => false, 'findAll' => true));
                 if ($n > 0) {
                     $sql .= " \n\tOR pages.id IN (\n";
                 }
                 $query->set('groupby', array());
                 $query->set('select', array('pages.id'));
                 $query->set('orderby', array());
                 // foreach($this->nativeWheres as $where) $query->where($where);  // doesn't seem to speed anything up, MySQL must already optimize for this
                 $sql .= tabIndent("\t\t" . $query->getQuery() . "\n)", 2);
                 $n++;
             }
             $sqls[] = $sql;
         }
         if (count($sqls)) {
             $sql = implode(" \n) AND (\n ", $sqls);
             $parentQuery->where("(\n{$sql}\n)");
         }
     }
     /* Possibly move existing subselectors to work like this rather than how they currently are
     		if(count($this->extraSubSelectors)) {
     			$sqls = array();
     			foreach($this->extraSubSelectors as $fieldName => $selectorGroup) {
     				$fieldName = $this->wire('database')->escapeCol($fieldName); 
     				$n = 0;
     				$sql = "\tpages.id IN (\n";
     				foreach($selectorGroup as $selectors) {
     					$pageFinder = new PageFinder();
     					$query = $pageFinder->find($selectors, array('returnQuery' => true, 'returnVerbose' => false));
     					if($n > 0) $sql .= " \n\tAND pages.id IN (\n";
     					$query->set('groupby', array());
     					$query->set('select', array('pages.id'));
     					$query->set('orderby', array());
     					// foreach($this->nativeWheres as $where) $query->where($where); 
     					$sql .= tabIndent("\t\t" . $query->getQuery() . "\n)", 2);
     					$n++;
     				}
     				$sqls[] = $sql;
     			}
     			if(count($sqls)) {
     				$sql = implode(" \n) AND (\n ", $sqls);
     				$parentQuery->where("(\n$sql\n)");
     			}
     		}
     		*/
 }
Exemplo n.º 2
0
 /**
  * Special case when field is native to the pages table
  *
  * TODO not all operators will work here, so may want to add some translation or filtering
  *
  */
 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->getFuel('fields')->isNativeName($field)) {
             $subfield = $field;
             $field = 'children';
         }
         if ($field == 'child') {
             $field = 'children';
         }
         if (in_array($field, array('parent', 'parent_id', 'children'))) {
             if (!$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;
                     }
                     // convert path to id
                     $parent = $this->fuel('pages')->get($v);
                     if (!$parent instanceof NullPage) {
                         $values[$k] = $parent->id;
                     } else {
                         $values[$k] = null;
                     }
                 }
                 $field = 'parent_id';
                 if ($field == 'parent_id' && 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')->isNativeName($subfield)) {
                     $finder = new PageFinder();
                     $s = $field == 'children' ? '' : 'children.count>0, ';
                     $matches = $finder->find(new Selectors("include=all, {$s}{$subfield}{$operator}" . implode('|', $values)));
                     foreach ($matches as $match) {
                         $IDs[] = (int) $match['id'];
                     }
                     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'))) {
                     // prepare value for created or modified date fields
                     if (!ctype_digit($value)) {
                         $value = strtotime($value);
                     }
                     $value = date('Y-m-d H:i:s', $value);
                 }
                 if ($field == 'name' && $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(wire('sanitizer')->pageName($word));
                         $s .= ($s ? ' AND ' : '') . "{$table}.{$field} RLIKE '" . '[[:<:]]' . $word . '[[:>:]]' . "'";
                     }
                 } else {
                     if ($field == 'name' && in_array($operator, array('%=', '^=', '$=', '%^=', '%$=', '*='))) {
                         // handle partial match to 'name' field
                         $value = $database->escapeStr(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 {
                             $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);
 }