diff --git a/code/AdvancedSearchForm.php b/code/AdvancedSearchForm.php new file mode 100755 index 00000000..aa10b047 --- /dev/null +++ b/code/AdvancedSearchForm.php @@ -0,0 +1,137 @@ + _t('AdvancedSearchForm.RELEVANCE', 'Relevance'), + 'LastUpdated' => _t('AdvancedSearchForm.LASTUPDATED', 'Last Updated'), + 'PageTitle' => _t('AdvancedSearchForm.PAGETITLE', 'Page Title'), + ), + 'Relevance' + ) + ), + $chooseDate = new CompositeField( + new HeaderField('LastUpdatedHeader',_t('AdvancedSearchForm.LASTUPDATEDHEADER', 'LAST UPDATED')), + new DateField("From", _t('AdvancedSearchForm.FROM', 'From')), + new DateField("To", _t('AdvancedSearchForm.TO', 'To')) + ) + ); + + $searchBy->ID = "AdvancedSearchForm_SearchBy"; + $searchOnly->ID = "AdvancedSearchForm_SearchOnly"; + $sortBy->ID = "AdvancedSearchForm_SortBy"; + $chooseDate->ID = "AdvancedSearchForm_ChooseDate"; + } + + if(!$actions) { + $actions = new FieldSet( + new FormAction("results", _t('AdvancedSearchForm.GO', 'Go')) + ); + } + parent::__construct($controller, $name, $fields, $actions); + } + + public function forTemplate(){ + return $this->renderWith(array("AdvancedSearchForm","Form")); + } + + /* Return dataObjectSet of the results, using the form data. + */ + public function getResults($numPerPage = 10) { + $data = $this->getData(); + + if($data['+']) $keywords .= " +" . ereg_replace(" +", " +", trim($data['+'])); + if($data['quote']) $keywords .= ' "' . $data['quote'] . '"'; + if($data['any']) $keywords .= ' ' . $data['any']; + if($data['-']) $keywords .= " -" . ereg_replace(" +", " -", trim($data['-'])); + $keywords = trim($keywords); + + // This means that they want to just find pages where there's *no* match + + if($keywords[0] == '-') { + $keywords = $data['-']; + $invertedMatch = true; + } + + + // Limit search to various sections + if($_REQUEST['OnlyShow']) { + $pageList = array(); + + // Find the associated pages + foreach($_REQUEST['OnlyShow'] as $section => $checked) { + $items = explode(",", $section); + foreach($items as $item) { + $page = DataObject::get_one('SiteTree', "\"URLSegment\" = '" . DB::getConn()->addslashes($item) . "'"); + $pageList[] = $page->ID; + if(!$page) user_error("Can't find a page called '$item'", E_USER_WARNING); + $page->loadDescendantIDListInto($pageList); + } + } + $contentFilter = "\"ID\" IN (" . implode(",", $pageList) . ")"; + + // Find the files associated with those pages + $fileList = DB::query("SELECT \"FileID\" FROM \"Page_ImageTracking\" WHERE \"PageID\" IN (" . implode(",", $pageList) . ")")->column(); + if($fileList) $fileFilter = "\"ID\" IN (" . implode(",", $fileList) . ")"; + else $fileFilter = " 1 = 2 "; + } + + if($data['From']) { + $filter .= ($filter?" AND":"") . " \"LastEdited\" >= '$data[From]'"; + } + if($data['To']) { + $filter .= ($filter?" AND":"") . " \"LastEdited\" <= '$data[To]'"; + } + + if($filter) { + $contentFilter .= ($contentFilter?" AND":"") . $filter; + $fileFilter .= ($fileFilter?" AND":"") . $filter; + } + + if($data['sortby']) { + $sorts = array( + 'LastUpdated' => '"LastEdited" DESC', + 'PageTitle' => '"Title" ASC', + 'Relevance' => '"Relevance" DESC', + ); + $sortBy = $sorts[$data['sortby']] ? $sorts[$data['sortby']] : $sorts['Relevance']; + } + + $keywords = $this->addStarsToKeywords($keywords); + + return $this->searchEngine($keywords, $numPerPage, $sortBy, $contentFilter, true, $fileFilter, $invertedMatch); + } + + function getSearchQuery() { + $data = $_REQUEST; + if($data['+']) $keywords .= " +" . ereg_replace(" +", " +", trim($data['+'])); + if($data['quote']) $keywords .= ' "' . $data['quote'] . '"'; + if($data['any']) $keywords .= ' ' . $data['any']; + if($data['-']) $keywords .= " -" . ereg_replace(" +", " -", trim($data['-'])); + + return trim($keywords); + } + +} + +?> \ No newline at end of file diff --git a/code/SearchForm.php b/code/SearchForm.php new file mode 100755 index 00000000..edb87ebd --- /dev/null +++ b/code/SearchForm.php @@ -0,0 +1,196 @@ +hasExtension('Translatable')) { + $fields->push(new HiddenField('locale', 'locale', Translatable::get_current_locale())); + } + + if(!$actions) { + $actions = new FieldSet( + new FormAction("getResults", _t('SearchForm.GO', 'Go')) + ); + } + + parent::__construct($controller, $name, $fields, $actions); + + $this->setFormMethod('get'); + + $this->disableSecurityToken(); + } + + public function forTemplate() { + return $this->renderWith(array( + 'SearchForm', + 'Form' + )); + } + + /** + * Set the classes to search. + * Currently you can only choose from "SiteTree" and "File", but a future version might improve this. + */ + function classesToSearch($classes) { + $illegalClasses = array_diff($classes, array('SiteTree', 'File')); + if($illegalClasses) { + user_error("SearchForm::classesToSearch() passed illegal classes '" . implode("', '", $illegalClasses) . "'. At this stage, only File and SiteTree are allowed", E_USER_WARNING); + } + $legalClasses = array_intersect($classes, array('SiteTree', 'File')); + $this->classesToSearch = $legalClasses; + } + + /** + * Get the classes to search + * + * @return array + */ + function getClassesToSearch() { + return $this->classesToSearch; + } + + /** + * Return dataObjectSet of the results using $_REQUEST to get info from form. + * Wraps around {@link searchEngine()}. + * + * @param int $pageLength DEPRECATED 2.3 Use SearchForm->pageLength + * @param array $data Request data as an associative array. Should contain at least a key 'Search' with all searched keywords. + * @return DataObjectSet + */ + public function getResults($pageLength = null, $data = null){ + // legacy usage: $data was defaulting to $_REQUEST, parameter not passed in doc.silverstripe.org tutorials + if(!isset($data) || !is_array($data)) $data = $_REQUEST; + + // set language (if present) + if(singleton('SiteTree')->hasExtension('Translatable') && isset($data['locale'])) { + $origLocale = Translatable::get_current_locale(); + Translatable::set_current_locale($data['locale']); + } + + $keywords = $data['Search']; + + $andProcessor = create_function('$matches',' + return " +" . $matches[2] . " +" . $matches[4] . " "; + '); + $notProcessor = create_function('$matches', ' + return " -" . $matches[3]; + '); + + $keywords = preg_replace_callback('/()("[^()"]+")( and )("[^"()]+")()/i', $andProcessor, $keywords); + $keywords = preg_replace_callback('/(^| )([^() ]+)( and )([^ ()]+)( |$)/i', $andProcessor, $keywords); + $keywords = preg_replace_callback('/(^| )(not )("[^"()]+")/i', $notProcessor, $keywords); + $keywords = preg_replace_callback('/(^| )(not )([^() ]+)( |$)/i', $notProcessor, $keywords); + + $keywords = $this->addStarsToKeywords($keywords); + + if(!$pageLength) $pageLength = $this->pageLength; + $start = isset($_GET['start']) ? (int)$_GET['start'] : 0; + + if(strpos($keywords, '"') !== false || strpos($keywords, '+') !== false || strpos($keywords, '-') !== false || strpos($keywords, '*') !== false) { + $results = DB::getConn()->searchEngine($this->classesToSearch, $keywords, $start, $pageLength, "\"Relevance\" DESC", "", true); + } else { + $results = DB::getConn()->searchEngine($this->classesToSearch, $keywords, $start, $pageLength); + } + + // filter by permission + if($results) foreach($results as $result) { + if(!$result->canView()) $results->remove($result); + } + + // reset locale + if(singleton('SiteTree')->hasExtension('Translatable') && isset($data['locale'])) { + Translatable::set_current_locale($origLocale); + } + + return $results; + } + + protected function addStarsToKeywords($keywords) { + if(!trim($keywords)) return ""; + // Add * to each keyword + $splitWords = preg_split("/ +/" , trim($keywords)); + while(list($i,$word) = each($splitWords)) { + if($word[0] == '"') { + while(list($i,$subword) = each($splitWords)) { + $word .= ' ' . $subword; + if(substr($subword,-1) == '"') break; + } + } else { + $word .= '*'; + } + $newWords[] = $word; + } + return implode(" ", $newWords); + } + + /** + * Get the search query for display in a "You searched for ..." sentence. + * + * @param array $data + * @return string + */ + public function getSearchQuery($data = null) { + // legacy usage: $data was defaulting to $_REQUEST, parameter not passed in doc.silverstripe.org tutorials + if(!isset($data)) $data = $_REQUEST; + + return Convert::raw2xml($data['Search']); + } + + /** + * Set the maximum number of records shown on each page. + * + * @param int $length + */ + public function setPageLength($length) { + $this->pageLength = $length; + } + + /** + * @return int + */ + public function getPageLength() { + return $this->pageLength; + } + +} + +?>