Permalink
Browse files

MINOR Moved AdvancedSearchForm, SearchForm from sapphire/search to cm…

…s module
  • Loading branch information...
1 parent fa7da8f commit c905bcb471fd20323e74ce98ba179e16ea8334f7 Paul Meyrick committed with chillu Mar 18, 2011
Showing with 333 additions and 0 deletions.
  1. +137 −0 code/AdvancedSearchForm.php
  2. +196 −0 code/SearchForm.php
View
@@ -0,0 +1,137 @@
+<?php
+/**
+ * More advanced search form
+ * @package cms
+ * @subpackage search
+ */
+class AdvancedSearchForm extends SearchForm {
+
+ /**
+ * the constructor of a Simple/basic SearchForm
+ */
+ function __construct($controller, $name, $fields = null, $actions = null) {
+ if(!$fields) {
+ $fields = new FieldSet(
+ $searchBy = new CompositeField(
+ new HeaderField('SearchByHeader',_t('AdvancedSearchForm.SEARCHBY', 'SEARCH BY')),
+ new TextField("+", _t('AdvancedSearchForm.ALLWORDS', 'All Words')),
+ new TextField("quote", _t('AdvancedSearchForm.EXACT', 'Exact Phrase')),
+ new TextField("any", _t('AdvancedSearchForm.ATLEAST', 'At Least One Of the Words')),
+ new TextField("-", _t('AdvancedSearchForm.WITHOUT', 'Without the Words'))
+ ),
+ $sortBy = new CompositeField(
+ new HeaderField('SortByHeader',_t('AdvancedSearchForm.SORTBY', 'SORT RESULTS BY')),
+ new OptionsetField("sortby", "",
+ array(
+ 'Relevance' => _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);
+ }
+
+}
+
+?>
View
@@ -0,0 +1,196 @@
+<?php
+/**
+ * Standard basic search form which conducts a fulltext search on all {@link SiteTree}
+ * objects.
+ *
+ * If multilingual content is enabled through the {@link Translatable} extension,
+ * only pages the currently set language on the holder for this searchform are found.
+ * The language is set through a hidden field in the form, which is prepoluated
+ * with {@link Translatable::get_current_locale()} when then form is constructed.
+ *
+ * @see Use ModelController and SearchContext for a more generic search implementation based around DataObject
+ * @package cms
+ * @subpackage search
+ */
+class SearchForm extends Form {
+
+ /**
+ * @var int $pageLength How many results are shown per page.
+ * Relies on pagination being implemented in the search results template.
+ */
+ protected $pageLength = 10;
+
+ /**
+ * Classes to search
+ */
+ protected $classesToSearch = array(
+ "SiteTree", "File"
+ );
+
+ /**
+ *
+ * @param Controller $controller
+ * @param string $name The name of the form (used in URL addressing)
+ * @param FieldSet $fields Optional, defaults to a single field named "Search". Search logic needs to be customized
+ * if fields are added to the form.
+ * @param FieldSet $actions Optional, defaults to a single field named "Go".
+ */
+ function __construct($controller, $name, $fields = null, $actions = null) {
+ if(!$fields) {
+ $fields = new FieldSet(
+ new TextField('Search', _t('SearchForm.SEARCH', 'Search')
+ ));
+ }
+
+ if(singleton('SiteTree')->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;
+ }
+
+}
+
+?>

0 comments on commit c905bcb

Please sign in to comment.