Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MINOR Moved AdvancedSearchForm, SearchForm from sapphire/search to cm…
…s module
- Loading branch information
Showing
2 changed files
with
333 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
|
||
} | ||
|
||
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
|
||
} | ||
|
||
?> |