silverstripe dataobject searchable

[亡魂溺海] 提交于 2019-12-18 06:48:29

问题


I´m trying to have certain DataObjects (News) displayed in the default SearchResult Page. So the result should display normal Pages and News.

Is there an easy way to accomplish that in Silverstripe 3? Or is it recommended to code it completely custom - I mean a custom controller/action which handles the search request and creates a result list, which I display then in a custom template?

I found this, but obviously search is disabled right now: https://github.com/arambalakjian/DataObjects-as-Pages

Thx and regards, Florian


回答1:


I usually but together a custom search function after enabling FulltextSearchable. So in _config.php I would have

FulltextSearchable::enable();
Object::add_extension('NewsStory', "FulltextSearchable('Name,Content')");

replacing Name and Content with whatever DBField you want to be searchable. And each searchable DataObject have this in their class to enable search indexes (pretty sure this needs to be added and run dev/build before enabling the extension, and only works on MySQL DB).

static $create_table_options = array(
  'MySQLDatabase' => 'ENGINE=MyISAM'
);

then in my PageController I have my custom searchForm and results functions.

Here is the search function that returns the search form, called with $search in the template:

public function search()
{       
  if($this->request && $this->request->requestVar('Search')) {
    $searchText = $this->request->requestVar('Search');
  }else{
    $searchText = 'Search';
  }

  $f = new TextField('Search', false, $searchText);

  $fields = new FieldList(
    $f
  );
  $actions = new FieldList(
    new FormAction('results', 'Go')
  );
  $form = new Form(
    $this,
    'search',
    $fields,
    $actions
  );
  //$form->disableSecurityToken();
  $form->setFormMethod('GET');
  $form->setTemplate('SearchForm');

  return $form;
}

and here the custom results function to handle the queries...

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();

  $mode = ' IN BOOLEAN MODE';
  //$mode = ' WITH QUERY EXPANSION';
  //$mode = '';

  $siteTreeClasses = array('Page');
  $siteTreeMatch = "MATCH( Title, MenuTitle, Content, MetaTitle, MetaDescription, MetaKeywords ) AGAINST ('$keyword'$mode)
                  + MATCH( Title, MenuTitle, Content, MetaTitle, MetaDescription, MetaKeywords ) AGAINST ('$keywordHTML'$mode)";

  $newsItemMatch = "MATCH( Name, Content ) AGAINST ('$keyword'$mode)
                  + MATCH( Name, Content ) AGAINST ('$keywordHTML'$mode)";

  //Standard pages
  foreach ( $siteTreeClasses as $c )
  {
    $query = DataList::create($c)
      ->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);
  }


  //news
  $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);


  //sorting results
  $pages->sort(array(
    'Relevance' => 'DESC',
    'Title' => 'ASC'
  ));      
  $news->sort(array(
    'Relevance' => 'DESC',
    'Date' => 'DESC'
  ));

  //output
  $data = array(
    'Pages' => $pages,
    'News' => $news,
    'Query' => $keyword
  ); 
  return $this->customise($data)->renderWith(array('Search','Page'));
}

I add all the Page classes I want to be searched and that extend SiteTree in the $siteTreeClasses array, and the News parts can be pretty much copied for any other DataObjectI need searchable.

I am not saying this is the best solution and this can definitely be improved on, but it works for me and this might be a good stating point.




回答2:


I have adapted @colymba's solution into a silverstripe module: https://github.com/burnbright/silverstripe-pagesearch

It allows setting the pagetype in the url.




回答3:


You'll need to substantially overwrite SearchForm->getResults(). It uses Database->searchEngine(), but those are tailored towards SiteTree and Page classes.

The "proper" solution is to feed the data into a search engine like Solr or Sphinx. We have the SS3-compatible "fulltextsearch" module for this purpose: https://github.com/silverstripe-labs/silverstripe-fulltextsearch It's going to take some upfront setup, and is only feasible if you can either host Solr yourself, or are prepared to pay for a SaaS provider. Once you've got it running though, the possibilities are endless, its a great tool!



来源:https://stackoverflow.com/questions/14483880/silverstripe-dataobject-searchable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!