/** * this should be used to take the generic $where_criteria and turn it into something * the interface can use (eg, for a SQL interface, the $where_criteria would be turned * into a valid SQL string). * * currently not supported: 'near' * * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html * * @param MingoTable $table * @param MingoCriteria $where_criteria * @return mixed return whatever you want, however you want to return it, whatever is easiest for you */ protected function normalizeCriteria(MingoTable $table, MingoCriteria $where_criteria = null) { $ret_map = array(); $ret_map['where_criteria'] = $where_criteria; $ret_map['limit'] = array(0, 0); $query = new Zend_Search_Lucene_Search_Query_Boolean(); if ($where_criteria !== null) { // add all the required search keys and their values... $criteria_where = $where_criteria->getWhere(); foreach ($criteria_where as $name => $map) { $subquery = null; $where_sql = ''; $where_val = array(); $required = true; if (is_array($map)) { $command = $where_criteria->normalizeCommand('in'); if (isset($map[$command])) { $subquery = $this->handleMulti($name, $map[$command], true); $required = true; } //if // according to: http://lucene.apache.org/java/2_4_0/queryparsersyntax.html // Lucene cannot do nin queries without something before it (eg, foo:1 NOT foo(2 3) but // (NOT foo(2 3) doesn't work) $command = $where_criteria->normalizeCommand('nin'); if (isset($map[$command])) { $subquery = $this->handleMulti($name, $map[$command], false); $required = false; } //if $command = $where_criteria->normalizeCommand('not'); if (isset($map[$command])) { $subquery = $this->handleEquals($name, $map[$command], false); } //if $command1 = $where_criteria->normalizeCommand('gte'); $command2 = $where_criteria->normalizeCommand('lte'); if (isset($map[$command1]) && isset($map[$command2])) { $subquery = $this->handleRange($name, $map[$command1], $map[$command2], true); } //if if (isset($map[$command1])) { $subquery = $this->handleRange($name, $map[$command1], null, true); } //if if (isset($map[$command2])) { $subquery = $this->handleRange($name, null, $map[$command2], true); } //if $command = $where_criteria->normalizeCommand('gt'); if (isset($map[$command])) { $subquery = $this->handleRange($name, $map[$command], null, false); } //if $command = $where_criteria->normalizeCommand('lt'); if (isset($map[$command])) { $subquery = $this->handleRange($name, null, $map[$command], false); } //if } else { if ($name === '_q') { $subquery = Zend_Search_Lucene_Search_QueryParser::parse($map); } else { $subquery = $this->handleEquals($name, $map, true); } //if/else } //if/else if ($subquery) { $query->addSubquery($subquery, $required); } //method } //foreach // limit offset... $offset = $where_criteria->getOffset(); $ret_map['limit'] = array($where_criteria->getLimit() + $offset, $offset); // caution from docs: // Please use caution when using a non-default search order; // the query needs to retrieve documents completely from an index, // which may dramatically reduce search performance. // http://framework.zend.com/manual/en/zend.search.lucene.searching.html#zend.search.lucene.searching.sorting if ($where_criteria->hasSort()) { $criteria_sort = $where_criteria->getSort(); $sort_list = array(); // build the sort sql... foreach ($criteria_sort as $name => $direction) { $sort_list[] = $name; $sort_list[] = SORT_REGULAR; ///$sort_list[] = SORT_STRING; ///SORT_NUMERIC; $sort_list[] = $direction > 0 ? SORT_ASC : SORT_DESC; } //foreach $ret_map['sort'] = $sort_list; } //if } //if $ret_map['query'] = $query; return $ret_map; }
/** * find the index table name from the table and the list of fields the index comprises * * @param MingoTable $table the main table's name * @param MingoCriteria $where_criteria * @return string the index table name */ protected function findIndexTableName(MingoTable $table, MingoCriteria $where_criteria) { if (!$where_criteria->hasWhere() && !$where_criteria->hasSort()) { return ''; } //if $ret_str = ''; $is_match = false; $where_map = $where_criteria->getWhere(); $sort_map = $where_criteria->getSort(); // php >= 5.3, use when Mingo is ported to namespaces... ///$field_list = array_keys(array_replace($where_map,$sort_map)); // we need to get a list of all the fields used in the order they will be used $field_list = array_keys($where_map); if (!empty($sort_map)) { $field_list = array_unique(array_merge($field_list, array_keys($sort_map))); } //if // now go through the index and see if it matches all the fields... foreach ($table->getIndexes() as $index) { $field_i = 0; foreach ($index->getFieldNames() as $field) { if (isset($field_list[$field_i])) { if ($field === $field_list[$field_i]) { $is_match = true; $field_i++; } else { $is_match = false; break; } //if/else } else { break; } //if/else } //foreach if ($is_match) { // we're done, we found a match... $ret_str = $this->getIndexTableName($table, $index); break; } //if } //foreach if (!$is_match) { // since we couldn't find an index table, make sure the query can be valid // on the main table // we are selecting on the main table (no index is being used) so we can only // select or sort on 4 fields (by default): _id, _created, and _updated foreach ($field_list as $field) { // if a field in the where map is not in the main table we've got trouble // since an index table couldn't be found if (!in_array($field, $this->non_body_fields)) { $e_msg = sprintf('Could not match fields: [%s] sorted by fields: [%s] with an index table.', join(',', array_keys($where_map)), join(',', array_keys($sort_map))); // list the available index tables if we are in debug mode... if ($this->hasDebug()) { $e_msg .= ' Indexes available: '; $index_list = $this->getIndexes($table); $e_index_list = array(); foreach ($index_list as $index) { $e_index_list[] = sprintf('%s(%s)', $index->getName(), join(',', $index->getFieldNames())); } //foreach $e_msg .= join(', ', $e_index_list); } //if throw new RuntimeException($e_msg); } //if } //foreach } //if/else return $ret_str; }