Extending FullTextSearch for DataObjects

Posted by Mo on 17 June 2011 | Comments

Tags: , ,

I have been wrestling over the problem of extending the default search functionality in Silverstripe to not only search Page objects, but other DataObjects as well.

In the end I came up with a workable solution thanks to the help of Katja Durrani over at the Silverstripe forum.

It seems that you can't currently get add searchable objects to FullTextSearchable by any means. Instead, you have to perform a bit of a hack (in my opinion) to the results method on your Page_Controller.

Before getting that far though, you first need to allow any DataObjects you want searched to be indexed. Do the following to your DataObject's model:


public static $indexes = array(
    "fulltext (Title, Content)"
);

Then rebuild your database (/dev/build/?flush=all).

Now you can go about adding your search form, as described in the Silverstripe docs. Once this is done, you need to change your results() method in Page_Controller to look more like this:


class Page_Controller extends ContentController {
...
    public function results($data, $form){
        $data = $_REQUEST; 
        
        $query = htmlspecialchars($data['Search'], ENT_QUOTES,'UTF-8'); 
        
        $pages = DataObject::get("SiteTree","MATCH (Title,Content) AGAINST ('$query' IN BOOLEAN MODE)");
        $studies = DataObject::get("CaseStudy","MATCH (Title,Content) AGAINST ('$query' IN BOOLEAN MODE)");
        
        $searchresults = new DataObjectSet();
        $searchresults->merge($pages);
        $searchresults->merge($studies);
        
        if($searchresults){ 
            $data['Results'] = $searchresults;           
        } else { 
            $data['Results'] = ''; 
        } 
        
        $data['Title'] = 'Search Results'; 

        return $this->customise($data)->renderWith(array('Search_results','Page')); 
    }
...
}

What this new method does, is use the submitted search to perform 2 queries:

  1. Query SiteTree and return any Objects that have match the search term
  2. Query the DataObject (in this case "CaseStudy") in the same way.

If you have more than one DataObject you want to query, you would need to add additional queries for each one.

Finally, you need to merge your two returned DataObjectSet's and then check if they contain any data.

Now you can return this to a custom template (for this example, I have used "Search_results') and there you go!

You can also find this code on Pastie