mirror of
https://github.com/silverstripe/silverstripe-docsviewer
synced 2024-10-22 11:05:56 +02:00
FEATURE: implemented initial cut of open search output and description functionality.
This commit is contained in:
parent
855f5471e4
commit
166fb8dff3
14
_config.php
14
_config.php
@ -7,7 +7,17 @@
|
||||
* For more information and documentation see sapphiredocs/docs/en
|
||||
*/
|
||||
|
||||
// default location for documentation
|
||||
// default location for documentation. If you want this under a custom url
|
||||
// define your own rule in your mysite/_config.php
|
||||
Director::addRules(100, array(
|
||||
'dev/docs' => 'DocumentationViewer'
|
||||
));
|
||||
));
|
||||
|
||||
// the default meta data for the OpenSearch library. More descriptive values
|
||||
// can be set in your mysite file
|
||||
DocumentationSearch::set_meta_data(array(
|
||||
'ShortName' => _t('DocumentationViewer.OPENSEARCHNAME', 'Documentation Search'),
|
||||
'Description' => _t('DocumentationViewer.OPENSEARCHDESC', 'Search the documentation'),
|
||||
'Contact' => Email::getAdminEmail(),
|
||||
'Tags' => _t('DocumentationViewer.OPENSEARCHTAGS', 'Documentation')
|
||||
));
|
||||
|
@ -3,19 +3,82 @@
|
||||
/**
|
||||
* Documentation Search powered by Lucene. You will need Zend_Lucene installed on your path
|
||||
* to rebuild the indexes run the {@link RebuildLuceneDocsIndex} task. You may wish to setup
|
||||
* a cron job to remake the indexes on a regular basis
|
||||
* a cron job to remake the indexes on a regular basis.
|
||||
*
|
||||
* It has the ability to generate an OpenSearch RSS formatted feeds simply by using the URL
|
||||
*
|
||||
* <code>
|
||||
* yoursite.com/search/?q=Foo&format=rss. // Format can either be specified as rss or left off.
|
||||
* </code>
|
||||
*
|
||||
* To get a specific amount of results you can also use the modifiers start and limit
|
||||
*
|
||||
* <code>
|
||||
* yoursite.com/search/?q=Foo&start=10&limit=10
|
||||
* </code>
|
||||
*
|
||||
* @package sapphiredocs
|
||||
*/
|
||||
|
||||
class DocumentationSearch {
|
||||
|
||||
class DocumentationSearch extends Controller {
|
||||
|
||||
/**
|
||||
* @var bool - Is search enabled
|
||||
*/
|
||||
private static $enabled = false;
|
||||
|
||||
/**
|
||||
* @var string - OpenSearch metadata. Please use {@link DocumentationSearch::set_meta_data()}
|
||||
*/
|
||||
private static $meta_data;
|
||||
|
||||
/**
|
||||
* @var DataObjectSet - Results
|
||||
*/
|
||||
private $results;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $totalResults;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $query;
|
||||
|
||||
/**
|
||||
* @var Controller
|
||||
*/
|
||||
private $outputController;
|
||||
|
||||
/**
|
||||
* Set the current search query
|
||||
*
|
||||
* @param string
|
||||
*/
|
||||
public function setQuery($query) {
|
||||
$this->query = $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current search query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getQuery() {
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DocumentationViewer} or {@link DocumentationSearch} instance which this search is rendering
|
||||
* on based on whether it is the results display or RSS feed
|
||||
*
|
||||
* @param Controller
|
||||
*/
|
||||
public function setOutputController($controller) {
|
||||
$this->outputController = $controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Folder name for indexes (in the temp folder). You can override it using
|
||||
@ -26,7 +89,8 @@ class DocumentationSearch {
|
||||
private static $index_location = 'sapphiredocs';
|
||||
|
||||
static $allowed_actions = array(
|
||||
'buildindex'
|
||||
'buildindex',
|
||||
'opensearch'
|
||||
);
|
||||
|
||||
/**
|
||||
@ -96,29 +160,28 @@ class DocumentationSearch {
|
||||
|
||||
/**
|
||||
* Perform a search query on the index
|
||||
*
|
||||
* Rebuilds the index if it out of date
|
||||
*/
|
||||
public function performSearch($query) {
|
||||
public function performSearch() {
|
||||
try {
|
||||
$index = Zend_Search_Lucene::open(self::get_index_location());
|
||||
|
||||
Zend_Search_Lucene::setResultSetLimit(200);
|
||||
|
||||
$this->results = $index->find($query);
|
||||
$this->results = $index->find($this->getQuery());
|
||||
$this->totalResults = $index->numDocs();
|
||||
}
|
||||
catch(Zend_Search_Lucene_Exception $e) {
|
||||
// the reindexing task has not been run
|
||||
user_error('DocumentationSearch::performSearch() could not perform search as index does not exist.
|
||||
Please run /dev/tasks/RebuildLuceneDocsIndex', E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DataObjectSet
|
||||
* @return ArrayData
|
||||
*/
|
||||
public function getDataArrayFromHits($request) {
|
||||
public function getSearchResults($request) {
|
||||
$pageLength = (isset($_GET['length'])) ? (int) $_GET['length'] : 10;
|
||||
|
||||
$data = array(
|
||||
'Results' => null,
|
||||
'Query' => null,
|
||||
@ -127,6 +190,7 @@ class DocumentationSearch {
|
||||
'TotalPages' => null,
|
||||
'ThisPage' => null,
|
||||
'StartResult' => null,
|
||||
'PageLength' => $pageLength,
|
||||
'EndResult' => null,
|
||||
'PrevUrl' => DBField::create('Text', 'false'),
|
||||
'NextUrl' => DBField::create('Text', 'false'),
|
||||
@ -136,7 +200,7 @@ class DocumentationSearch {
|
||||
$start = ($request->requestVar('start')) ? (int)$request->requestVar('start') : 0;
|
||||
$query = ($request->requestVar('Search')) ? $request->requestVar('Search') : '';
|
||||
|
||||
$pageLength = 10;
|
||||
|
||||
$currentPage = floor( $start / $pageLength ) + 1;
|
||||
|
||||
$totalPages = ceil(count($this->results) / $pageLength );
|
||||
@ -204,10 +268,12 @@ class DocumentationSearch {
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
return new ArrayData($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a nice query string for the results
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function buildQueryUrl($params) {
|
||||
@ -232,9 +298,79 @@ class DocumentationSearch {
|
||||
return (int) $this->totalResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimizes the search indexes on the File System
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function optimizeIndex() {
|
||||
$index = Zend_Search_Lucene::open(self::get_index_location());
|
||||
|
||||
if($index) $index->optimize();
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return ($this->outputController) ? $this->outputController->Title : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenSearch MetaData. Includes 'description', 'tags', 'contact'
|
||||
*
|
||||
* @param array
|
||||
*/
|
||||
public static function set_meta_data($data) {
|
||||
if(is_array($data)) {
|
||||
foreach($data as $key => $value) {
|
||||
self::$meta_data[strtolower($key)] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the meta data needed by opensearch.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_meta_data() {
|
||||
$data = self::$meta_data;
|
||||
|
||||
return array(
|
||||
'Description' => (isset($data['description'])) ? $data['description'] : "",
|
||||
'Tags' => (isset($data['tags'])) ? $data['tags'] : "",
|
||||
'Contact' => (isset($data['contact'])) ? $data['contact'] : "",
|
||||
'ShortName' => (isset($data['shortname'])) ? $data['shortname'] : ""
|
||||
);
|
||||
}
|
||||
|
||||
public function renderResults() {
|
||||
if(!$this->results) $this->performSearch();
|
||||
if(!$this->outputController) $this->outputController = $this;
|
||||
|
||||
$request = $this->outputController->getRequest();
|
||||
|
||||
$data = $this->getSearchResults($request);
|
||||
$templates = array('DocumentationViewer_results', 'DocumentationViewer');
|
||||
|
||||
if($request->requestVar('format') && $request->requestVar('format') == "rss") {
|
||||
// alter the fields for the opensearch xml.
|
||||
$title = ($title = $this->getTitle()) ? ' | '. $title : "";
|
||||
|
||||
$data->setField('Title', $data->Title . $title);
|
||||
|
||||
$data->setField('DescriptionURL', 'DocumentationSearch/opensearch/');
|
||||
|
||||
array_unshift($templates, 'OpenSearchResults');
|
||||
}
|
||||
|
||||
return $this->outputController->customise($data)->renderWith($templates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the opensearch description of the search results
|
||||
*/
|
||||
public function opensearch() {
|
||||
$data = self::get_meta_data();
|
||||
|
||||
return $this->customise(new ArrayData($data))->renderWith(array('OpenSearchDescription'));
|
||||
}
|
||||
}
|
@ -709,12 +709,11 @@ class DocumentationViewer extends Controller {
|
||||
/**
|
||||
* Past straight to results, display and encode the query
|
||||
*/
|
||||
function results($data, $form, $request) {
|
||||
function results($data, $form, $request) {
|
||||
$search = new DocumentationSearch();
|
||||
$search->performSearch($form->dataFieldByName('Search')->dataValue());
|
||||
$search->setQuery($form->dataFieldByName('Search')->dataValue());
|
||||
$search->setOutputController($this);
|
||||
|
||||
$data = $search->getDataArrayFromHits($request);
|
||||
|
||||
return $this->customise($data)->renderWith(array('DocumentationViewer_results', 'DocumentationViewer'));
|
||||
return $search->renderResults();
|
||||
}
|
||||
}
|
0
lang/_manifest_exclude
Executable file
0
lang/_manifest_exclude
Executable file
10
lang/en_US.php
Executable file
10
lang/en_US.php
Executable file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
global $lang;
|
||||
|
||||
$lang['en_US']['DocumentationSearch']['SEARCHRESULTS'] = 'Search Results';
|
||||
$lang['en_US']['DocumentationViewer']['CHANGE'] = 'Change';
|
||||
$lang['en_US']['DocumentationViewer']['LANGUAGE'] = 'Language';
|
||||
$lang['en_US']['DocumentationViewer']['SEARCH'] = 'Search';
|
||||
|
||||
?>
|
10
templates/OpenSearchDescription.ss
Normal file
10
templates/OpenSearchDescription.ss
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||
|
||||
<ShortName>$ShortName</ShortName>
|
||||
<Description>$Description</Description>
|
||||
<Tags>$Tags</Tags>
|
||||
<Contact>$Content</Contact>
|
||||
|
||||
<Url type="application/rss+xml" template="http://example.com/?q={searchTerms}&pw={startPage?}&format=rss"/>
|
||||
</OpenSearchDescription>
|
23
templates/OpenSearchResults.ss
Normal file
23
templates/OpenSearchResults.ss
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>$Title</title>
|
||||
<link>$Link</link>
|
||||
|
||||
<opensearch:totalResults>$TotalResults</opensearch:totalResults>
|
||||
<opensearch:startIndex>$StartResult</opensearch:startIndex>
|
||||
<opensearch:itemsPerPage>$PageLength</opensearch:itemsPerPage>
|
||||
|
||||
<atom:link rel="search" type="application/opensearchdescription+xml" href="{$BaseHref}DocumentationSearch/opensearch"/>
|
||||
|
||||
<opensearch:Query role="request" searchTerms="$Query" startPage="1" />
|
||||
|
||||
<% control Results %>
|
||||
<item>
|
||||
<title>$Title</title>
|
||||
<link>$Link</link>
|
||||
<description>$Content.LimitCharacters(200)</description>
|
||||
</item>
|
||||
<% end_control %>
|
||||
</channel>
|
||||
</rss>
|
Loading…
Reference in New Issue
Block a user