function search() { $urlSeparator = "_"; //Used for url parameters that pass something more than just a value $simplesearch_custom_fields = 1; // Search custom fields in simple search $simplesearch_query_type = 'all'; // any|all $min_word_chars = 3; // Only words with min_word_chars or higher will be used in any|all query types $category_ids = ''; $criteria_ids = Sanitize::getString($this->params, 'criteria'); $dir_id = Sanitize::getString($this->params, 'dir', ''); $accepted_query_types = array('any', 'all', 'exact'); $query_type = Sanitize::getString($this->params, 'query'); $keywords = urldecode(Sanitize::getString($this->params, 'keywords')); $scope = Sanitize::getString($this->params, 'scope'); $author = urldecode(Sanitize::getString($this->params, 'author')); $ignored_search_words = $keywords != '' ? cmsFramework::getIgnoredSearchWords() : array(); if (!in_array($query_type, $accepted_query_types)) { $query_type = 'all'; // default value if value used is not recognized } // Build search where statement for standard fields $wheres = array(); # SIMPLE SEARCH if ($keywords != '' && $scope == '') { // $scope = array("Listing.title","Listing.introtext","Listing.fulltext","Review.comments","Review.title"); $scope = array("Listing.title", "Listing.introtext", "Listing.fulltext", "Listing.metakey"); $words = array_unique(explode(' ', $keywords)); // Include custom fields if ($simplesearch_custom_fields == 1) { $tbcols = $this->_db->getTableFields(array('#__jreviews_content')); $fields = array_keys($tbcols['#__jreviews_content']); $ignore = array("email", "contentid", "featured"); // TODO: find out which fields have predefined selection values to get the searchable values instead of reference } $whereFields = array(); foreach ($scope as $contentfield) { $whereContentFields = array(); foreach ($words as $word) { if (strlen($word) >= $min_word_chars && !in_array($word, $ignored_search_words)) { $word = urldecode(trim($word)); $whereContentFields[] = " {$contentfield} LIKE " . $this->quoteLike($word); } } if (!empty($whereContentFields)) { $whereFields[] = " (" . implode($simplesearch_query_type == 'all' ? ') AND (' : ') OR (', $whereContentFields) . ')'; } } if ($simplesearch_custom_fields == 1) { // add custom fields to where statement foreach ($fields as $field) { $whereCustomFields = array(); foreach ($words as $word) { $word = urldecode($word); if (strlen($word) >= $min_word_chars && !in_array($word, $ignored_search_words)) { if (!in_array($field, $ignore)) { $whereCustomFields[] = "{$field} LIKE " . $this->quoteLike($word); } } } if (!empty($whereCustomFields) && !in_array($field, $ignore)) { $whereFields[] = "\n(" . implode($simplesearch_query_type == 'all' ? ') AND (' : ') OR (', $whereCustomFields) . ')'; } } } if (!empty($whereFields)) { $wheres[] = "\n(" . implode(') OR (', $whereFields) . ')'; } } else { # ADVANCED SEARCH // Process core content fields and reviews if ($keywords != '' && $scope != '') { $allowedContentFields = array("title", "introtext", "fulltext", "reviews", "metakey"); $scope = explode($urlSeparator, $scope); $scope[] = 'metakey'; switch ($query_type) { case 'exact': foreach ($scope as $contentfield) { if (in_array($contentfield, $allowedContentFields)) { $w = array(); if ($contentfield == 'reviews') { $w[] = " Review.comments LIKE " . $this->quoteLike($keywords); $w[] = " Review.title LIKE " . $this->quoteLike($keywords); } else { $w[] = " Listing.{$contentfield} LIKE " . $this->quoteLike($keywords); } $whereContentOptions[] = "\n" . implode(' OR ', $w); } } $wheres[] = implode(' OR ', $whereContentOptions); break; case 'any': case 'all': default: $words = array_unique(explode(' ', $keywords)); $whereFields = array(); foreach ($scope as $contentfield) { if (in_array($contentfield, $allowedContentFields)) { $whereContentFields = array(); $whereReviewComment = array(); $whereReviewTitle = array(); foreach ($words as $word) { if (strlen($word) >= $min_word_chars && !in_array($word, $ignored_search_words)) { if ($contentfield == 'reviews') { $whereReviewComment[] = "Review.comments LIKE " . $this->quoteLike($word); $whereReviewTitle[] = "Review.title LIKE " . $this->quoteLike($word); } else { $whereContentFields[] = "Listing.{$contentfield} LIKE " . $this->quoteLike($word); } } } if ($contentfield == 'reviews') { $whereFields[] = "\n(" . implode($query_type == 'all' ? ') AND (' : ') OR (', $whereReviewTitle) . ")"; $whereFields[] = "\n(" . implode($query_type == 'all' ? ') AND (' : ') OR (', $whereReviewComment) . ")"; } else { $whereFields[] = "\n(" . implode($query_type == 'all' ? ') AND (' : ') OR (', $whereContentFields) . ")"; } } } $wheres[] = '(' . implode(') OR (', $whereFields) . ')'; break; } } else { $scope = array(); } // Process author field if ($author && $this->Config->search_item_author) { $wheres[] = "( User.name LIKE " . $this->quoteLike($author) . " OR " . "\n User.username LIKE " . $this->quoteLike($author) . " OR " . "\n Listing.created_by_alias LIKE " . $this->quoteLike($author) . " )"; } // Process custom fields $query_string = Sanitize::getString($this->passedArgs, 'url'); if ($tag = Sanitize::getVar($this->params, 'tag')) { $this->click2search = true; // Field value underscore fix: remove extra menu parameter not removed in routes regex $tag['value'] = preg_replace(array('/_m[0-9]+$/', '/_m$/', '/_$/'), '', $tag['value']); // Below is included fix for dash to colon change in J1.5 $query_string = 'jr_' . $tag['field'] . _PARAM_CHAR . str_replace(':', '-', $tag['value']) . '/' . $query_string; } $url_array = explode("/", $query_string); // Include external parameters for custom fields - this is required for components such as sh404sef foreach ($this->params as $varName => $varValue) { if (substr($varName, 0, 3) == "jr_" && false === array_search($varName . _PARAM_CHAR . $varValue, $url_array)) { $url_array[] = $varName . _PARAM_CHAR . $varValue; } } // Get names of custom fields to eliminate queries on non-existent fields $customFieldsMeta = $this->_db->getTableFields(array('#__jreviews_content')); $customFields = is_array($customFieldsMeta['#__jreviews_content']) ? array_keys($customFieldsMeta['#__jreviews_content']) : array(); /**************************************************************************** * First pass of url params to get all field names and then find their types ****************************************************************************/ $fieldNameArray = array(); foreach ($url_array as $url_param) { $param = explode(":", $url_param); $key = $param[0]; $value = Sanitize::getVar($param, '1', null); // '1' is the key where the value is stored in $param if (substr($key, 0, 3) == "jr_" && in_array($key, $customFields) && !is_null($value) && $value != '') { $fieldNameArray[$key] = $value; } } // Find out the field type to determine whether it's an AND or OR search if (!empty($fieldNameArray)) { $query = ' SELECT name, type FROM #__jreviews_fields WHERE name IN (' . $this->quote(array_keys($fieldNameArray)) . ')'; $this->_db->setQuery($query); $fieldTypesArray = $this->_db->loadAssocList('name'); } $OR_fields = array("select", "radiobuttons"); // Single option $AND_fields = array("selectmultiple", "checkboxes"); // Multiple option foreach ($fieldNameArray as $key => $value) { $searchValues = explode($urlSeparator, $value); $fieldType = $fieldTypesArray[$key]['type']; // Process values with separator for multiple values or operators. The default separator is an underscore if (substr_count($value, $urlSeparator)) { // Check if it is a numeric or date value $allowedOperators = array("equal" => '=', "higher" => '>=', "lower" => '<=', "between" => 'between'); $operator = $searchValues[0]; $isDate = false; if ($searchValues[1] == "date") { $isDate = true; } if (in_array($operator, array_keys($allowedOperators)) && (is_numeric($searchValues[1]) || $isDate)) { if ($operator == "between") { if ($isDate) { @($searchValues[1] = low($searchValues[2]) == 'today' ? _TODAY : $searchValues[2]); @($searchValues[2] = low($searchValues[3]) == 'today' ? _TODAY : $searchValues[3]); } $low = is_numeric($searchValues[1]) ? $searchValues[1] : $this->quote($searchValues[1]); $high = is_numeric($searchValues[2]) ? $searchValues[2] : $this->quote($searchValues[2]); $wheres[] = "\n" . $key . " BETWEEN " . $low . ' AND ' . $high; } else { if ($searchValues[1] == "date") { $searchValues[1] = low($searchValues[2]) == 'today' ? _TODAY : $searchValues[2]; } $value = is_numeric($searchValues[1]) ? $searchValues[1] : $this->quote($searchValues[1]); $wheres[] = "\n" . $key . $allowedOperators[$operator] . $value; } } else { // This is a field with pre-defined options $whereFields = array(); if (isset($tag) && ($key = 'jr_' . $tag['field'])) { // Field value underscore fix if (in_array($fieldType, $OR_fields)) { $whereFields[] = " {$key} = '*" . $this->quote('*' . urldecode($value) . '*'); } else { $whereFields[] = " {$key} LIKE " . $this->quote('%*' . urldecode($value) . '*%'); } } elseif (!empty($searchValues)) { foreach ($searchValues as $value) { $searchValue = urldecode($value); if (in_array($fieldType, $OR_fields)) { $whereFields[] = " {$key} = " . $this->quote('*' . $value . '*'); } else { $whereFields[] = " {$key} LIKE " . $this->quote('%*' . $value . '*%'); } } } if (in_array($fieldType, $OR_fields)) { // Single option field $wheres[] = '(' . implode(') OR (', $whereFields) . ')'; } else { // Multiple option field $wheres[] = '(' . implode(') AND (', $whereFields) . ')'; } } } else { $value = urldecode($value); $whereFields = array(); if (in_array($fieldType, $OR_fields)) { $whereFields[] = " {$key} = " . $this->quote('*' . $value . '*'); } elseif (in_array($fieldType, $AND_fields)) { $whereFields[] = " {$key} LIKE " . $this->quote('%*' . $value . '*%'); } elseif (in_array($fieldType, array('integer', 'decimal'))) { // Does an exact search for numeric fields $words = explode(' ', trim($value)); foreach ($words as $word) { $whereFields[] = "{$key} = " . $this->quote($word); } } else { $whereFields[] = " {$key} LIKE " . $this->quoteLike($value); } $wheres[] = " (" . implode(') AND (', $whereFields) . ")"; } } // endforeach } $where = !empty($wheres) ? "\n (" . implode(") AND (", $wheres) . ")" : ''; // Determine which categories to include in the queries if ($cat_id = Sanitize::getString($this->params, 'cat')) { $section_ids = array(); $category_ids = explode($urlSeparator, $this->params['cat']); // Remove empty or nonpositive values from array if (!empty($category_ids)) { foreach ($category_ids as $index => $value) { // Check if it's a section if ($value[0] == 's' && is_numeric(substr($value, 1)) && substr($value, 1) > 0) { $section_ids[] = substr($value, 1); unset($category_ids[$index]); // It's a section, not a category } elseif (empty($value) || $value < 1 || !is_numeric($value)) { unset($category_ids[$index]); } } } $section_ids = implode(',', $section_ids); $category_ids = is_array($category_ids) ? implode(',', $category_ids) : $category_ids; $category_ids != '' and $this->params['cat'] = $category_ids; $section_ids != '' and $this->params['section'] = $section_ids; } elseif (isset($criteria_ids) && trim($criteria_ids) != '') { $criteria_ids = str_replace($urlSeparator, ',', $criteria_ids); $criteria_ids != '' and $this->params['criteria'] = $criteria_ids; } elseif (isset($dir_id) && trim($dir_id) != '') { $dir_id = str_replace($urlSeparator, ',', $dir_id); $dir_id != '' and $this->params['dir'] = $dir_id; } # Add search conditions to Listing model if ($where != '') { $this->Listing->conditions[] = $where; } elseif (empty($this->Listing->conditions) && $dir_id == '' && $category_ids == '' && $criteria_ids == '' && ($this->cmsVersion == CMS_JOOMLA15 && $section_ids == '' || $this->cmsVersion != CMS_JOOMLA15) && !Sanitize::getBool($this->Config, 'search_return_all', false)) { return $this->render('listings', 'listings_noresults'); } return $this->listings(); }