Create a gist now

Instantly share code, notes, and snippets.

SilverStripe custom search results function. For Page and DataObject
/**
* Process and render search results.
*
* !! NOTE
* _config.php includes:
*
* FulltextSearchable::enable();
* Object::add_extension('ExtendedPage', "FulltextSearchable('HeadlineText')");
* Object::add_extension('NewsStory', "FulltextSearchable('Name,Content')");
* !!
*
* @param array $data The raw request data submitted by user
* @param Form $form The form instance that was submitted
* @param SS_HTTPRequest $request Request generated for this action
*/
function results($data, $form, $request)
{
$keyword = trim($request->requestVar('Search'));
$keyword = Convert::raw2sql($keyword);
$keywordHTML = htmlentities($keyword, ENT_NOQUOTES, 'UTF-8');
$pages = new ArrayList();
$news = new ArrayList();
$files = new ArrayList();
$mode = ' IN BOOLEAN MODE';
//$mode = ' WITH QUERY EXPANSION';
//$mode = '';
$siteTreeClasses = array('Page', 'ExtendedPage'); //add in an classes that extend Page or SiteTree
$siteTreeMatch = "MATCH( Title, MenuTitle, Content, MetaTitle, MetaDescription, MetaKeywords ) AGAINST ('$keyword'$mode)
+ MATCH( Title, MenuTitle, Content, MetaTitle, MetaDescription, MetaKeywords ) AGAINST ('$keywordHTML'$mode)";
//custom MATCH statement for any Object that extend Page or SiteTree and have additional fields/columns that need to be searchable
//create one block per Object
//i.e. "MATCH( column1, column2, column3 ) AGAINST ('$keyword'$mode) + MATCH( column1, column2, column3 ) AGAINST ('$keywordHTML'$mode)"
$extendedPageMatch = "MATCH( HeadlineText ) AGAINST ('$keyword'$mode)
+ MATCH( HeadlineText ) AGAINST ('$keywordHTML'$mode)";
//DataObject
$newsItemMatch = "MATCH( Name, Content ) AGAINST ('$keyword'$mode)
+ MATCH( Name, Content ) AGAINST ('$keywordHTML'$mode)";
$fileMatch = "MATCH( Filename, Title, Content ) AGAINST ('$keyword'$mode)
+ MATCH( Filename, Title, Content ) AGAINST ('$keywordHTML'$mode)";
/*
* Standard pages
* SiteTree Classes with the default search MATCH
*/
foreach ( $siteTreeClasses as $c )
{
$query = DataList::create($c)
->filter(array('RootLanguageParentID' => $this->RootLanguageParentID))
->where($siteTreeMatch);
$query = $query->dataQuery()->query();
$query->addSelect(array('Relevance' => $siteTreeMatch));
$records = DB::query($query->sql());
$objects = array();
foreach( $records as $record )
{
if ( in_array($record['ClassName'], $siteTreeClasses) )
$objects[] = new $record['ClassName']($record);
}
$pages->merge($objects);
}
/*
* Pages with additional searchable fields
* copy/edit this block for each Object that extend Page/SiteTree and have other columns searchable
* see above for custom MATCH statement
*/
$query = DataList::create('ExtendedPage')
->where($siteTreeMatch . ' OR ' . $extendedPageMatch);
$query = $query->dataQuery()->query();
$query->addSelect(array('Relevance' => $siteTreeMatch . ' OR ' . $extendedPageMatch));
$records = DB::query($query->sql());
$objects = array();
foreach( $records as $record ) $objects[] = new $record['ClassName']($record);
$pages->merge($objects);
$pages->removeDuplicates();
/*
* news DataObject
*/
$query = DataList::create('NewsStory')->where($newsItemMatch);
$query = $query->dataQuery()->query();
$query->addSelect(array('Relevance' => $newsItemMatch));
$records = DB::query($query->sql());
$objects = array();
foreach( $records as $record ) $objects[] = new $record['ClassName']($record);
$news->merge($objects);
/*
* files
*/
$query = DataList::create('File')->where($fileMatch);
$query = $query->dataQuery()->query();
$query->addSelect(array('Relevance' => $fileMatch));
$records = DB::query($query->sql());
$objects = array();
foreach( $records as $record )
{
$extension = strtolower( pathinfo( $record['Name'], PATHINFO_EXTENSION ) );
//only return some file extensions
if ( in_array($extension, array('xls','xlsx','doc','docx','pdf','rtf','zip','7z','rar')) )
$objects[] = new $record['ClassName']($record);
}
$files->merge($objects);
/* ** */
$pages->sort(array(
'Relevance' => 'DESC',
'Title' => 'ASC'
));
$news->sort(array(
'Relevance' => 'DESC',
'Date' => 'DESC'
));
$files->sort(array(
'Relevance' => 'DESC',
'Name' => 'ASC'
));
$data = array(
'Pages' => $pages,
'News' => $news,
'Files' => $files,
'Query' => $keyword
);
if ( $pages->count() == 0
&& $news->count() == 0
&& $files->count() == 0 )
{
$data['NoResults'] = 1;
}
return $this->customise($data)->renderWith(array('Search','Page'));
}
@DiscoPixel

Hi colymba,
have you gotten your great fulltext results (including DataObjects) working with SilverStripe 3.3 yet?
I upgraded a website and the search led to a DB error:
MATCH(Title,MenuTitle,Content,MetaDescription) AGAINST ('lorem*' IN BOOLEAN MODE)) AND ("SiteTree_Live"."ClassName" IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)) ORDER BY "SiteTree_Live"."Sort" ASC You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment