mirror of
https://github.com/silverstripe/silverstripe-docsviewer
synced 2024-10-22 11:05:56 +02:00
APICHANGE: rather than passing the structure through the constructor, do so via setters which will allow us more flexibility
This commit is contained in:
parent
ac5ce3872e
commit
d2eb92233e
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A specific page within a {@link DocumentationEntity}.
|
||||
* Has to represent an actual file, please use {@link DocumentationViewer}
|
||||
@ -18,27 +19,16 @@ class DocumentationPage extends ViewableData {
|
||||
*/
|
||||
protected $relativePath;
|
||||
|
||||
/**
|
||||
* @var String
|
||||
*/
|
||||
protected $lang = 'en';
|
||||
|
||||
/**
|
||||
* @var String
|
||||
*/
|
||||
protected $version;
|
||||
|
||||
function __construct($relativePath, $entity, $lang = null, $version = null) {
|
||||
$this->entity = $entity;
|
||||
$this->relativePath = $relativePath;
|
||||
if($lang) $this->lang = $lang;
|
||||
if($version) $this->version = $version;
|
||||
|
||||
if(!file_exists($this->getPath())) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Path could not be found. Module path: %s, file path: %s',
|
||||
$this->entity->getPath(),
|
||||
$this->relativePath
|
||||
));
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DocumentationEntity
|
||||
*/
|
||||
@ -46,6 +36,10 @@ class DocumentationPage extends ViewableData {
|
||||
return $this->entity;
|
||||
}
|
||||
|
||||
function setEntity($entity) {
|
||||
$this->entity = $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return String Relative path to file or folder within the entity (including file extension),
|
||||
* but excluding version or language folders.
|
||||
@ -54,24 +48,45 @@ class DocumentationPage extends ViewableData {
|
||||
return $this->relativePath;
|
||||
}
|
||||
|
||||
function setRelativePath($path) {
|
||||
$this->relativePath = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute path including version and lang folder.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
function getPath() {
|
||||
$path = rtrim($this->entity->getPath($this->version, $this->lang), '/') . '/' . $this->getRelativePath();
|
||||
return realpath($path);
|
||||
$path = realpath(rtrim($this->entity->getPath($this->version, $this->lang), '/') . '/' . $this->getRelativePath());
|
||||
|
||||
if(!file_exists($path)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Path could not be found. Module path: %s, file path: %s',
|
||||
$this->entity->getPath(),
|
||||
$this->relativePath
|
||||
));
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
function getLang() {
|
||||
return $this->lang;
|
||||
}
|
||||
|
||||
function setLang($lang) {
|
||||
$this->lang = $lang;
|
||||
}
|
||||
|
||||
function getVersion() {
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
function setVersion($version) {
|
||||
$this->version = $version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return String
|
||||
*/
|
||||
@ -86,5 +101,4 @@ class DocumentationPage extends ViewableData {
|
||||
function getHTML($baselink = null) {
|
||||
return DocumentationParser::parse($this, $baselink);
|
||||
}
|
||||
|
||||
}
|
@ -391,6 +391,7 @@ class DocumentationParser {
|
||||
* @param bool Recursive search
|
||||
* @param DataObjectSet set of pages matched so far
|
||||
*
|
||||
* @throws Exception
|
||||
* @return DataObjectSet
|
||||
*/
|
||||
public static function get_pages_from_folder($folder, $recursive = false, &$pages = false) {
|
||||
@ -398,6 +399,8 @@ class DocumentationParser {
|
||||
|
||||
if(!$pages) $pages = new DataObjectSet();
|
||||
|
||||
if(!is_dir($folder)) throw new Exception(sprintf('%s is not a folder', $folder));
|
||||
|
||||
$handle = opendir($folder);
|
||||
|
||||
if($handle) {
|
||||
|
@ -4,31 +4,45 @@
|
||||
* @todo caching?
|
||||
*/
|
||||
|
||||
class DocumentationSearch extends Controller {
|
||||
class DocumentationSearch extends DocumentationViewer {
|
||||
|
||||
static $casting = array(
|
||||
'Query' => 'Text'
|
||||
);
|
||||
|
||||
static $allowed_actions = array('xml', 'search');
|
||||
|
||||
/**
|
||||
* @var array Cached search results
|
||||
*/
|
||||
private $searchCache = array();
|
||||
|
||||
/**
|
||||
* @var Int Page Length
|
||||
*/
|
||||
private $pageLength = 10;
|
||||
|
||||
/**
|
||||
* Generates the XML tree for {@link Sphinx} XML Pipes
|
||||
*
|
||||
* @uses DomDocument
|
||||
*/
|
||||
function sphinxxml() {
|
||||
function xml() {
|
||||
DocumentationService::load_automatic_registration();
|
||||
|
||||
|
||||
// generate the head of the document
|
||||
$dom = new DomDocument('1.0');
|
||||
$dom->encoding = "utf-8";
|
||||
$dom->formatOutput = true;
|
||||
$root = $dom->appendChild($dom->createElement('sphinx:docset'));
|
||||
$root = $dom->appendChild($dom->createElementNS('http://sphinxsearch.com', 'sphinx:docset'));
|
||||
|
||||
$schema = $dom->createElement('sphinx:schema');
|
||||
|
||||
$field = $dom->createElement('sphinx:field');
|
||||
$attr = $dom->createElement('sphinx:attr');
|
||||
|
||||
foreach(array('Title','Content', 'Language', 'Version', 'Module') as $field) {
|
||||
foreach(array('Title','Content', 'Language', 'Module', 'Path') as $field) {
|
||||
$node = $dom->createElement('sphinx:field');
|
||||
$node->setAttribute('name', $field);
|
||||
$node->setAttribute('name', strtolower($field));
|
||||
|
||||
$schema->appendChild($node);
|
||||
}
|
||||
@ -42,10 +56,11 @@ class DocumentationSearch extends Controller {
|
||||
foreach($pages as $doc) {
|
||||
$node = $dom->createElement('sphinx:document');
|
||||
|
||||
$node->setAttribute('ID', $doc->ID);
|
||||
$node->setAttribute('id', $doc->ID);
|
||||
|
||||
foreach($doc->getArray() as $key => $value) {
|
||||
if($key == 'ID') continue;
|
||||
$key = strtolower($key);
|
||||
if($key == 'id') continue;
|
||||
|
||||
$tmp = $dom->createElement($key);
|
||||
$tmp->appendChild($dom->createTextNode($value));
|
||||
@ -75,6 +90,7 @@ class DocumentationSearch extends Controller {
|
||||
if($modules) {
|
||||
foreach($modules as $module) {
|
||||
foreach($module->getLanguages() as $language) {
|
||||
try {
|
||||
$pages = DocumentationParser::get_pages_from_folder($module->getPath(false, $language));
|
||||
|
||||
if($pages) {
|
||||
@ -82,14 +98,52 @@ class DocumentationSearch extends Controller {
|
||||
$output->push(new ArrayData(array(
|
||||
'Title' => $page->Title,
|
||||
'Content' => file_get_contents($page->Path),
|
||||
'Path' => $page->Path,
|
||||
'Language' => $language,
|
||||
'ID' => base_convert(substr(md5($page->Path), -8), 16, 10)
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception $e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a search from the URL, performs a sphinx search and displays a search results
|
||||
* template.
|
||||
*
|
||||
* @todo Add additional language / version filtering
|
||||
*/
|
||||
function search() {
|
||||
$query = (isset($this->urlParams['ID'])) ? $this->urlParams['ID'] : false;
|
||||
$results = false;
|
||||
$keywords = "";
|
||||
|
||||
if($query) {
|
||||
$keywords = urldecode($query);
|
||||
|
||||
$start = isset($_GET['start']) ? (int)$_GET['start'] : 0;
|
||||
|
||||
$cachekey = $query.':'.$start;
|
||||
|
||||
if(!isset($this->searchCache[$cachekey])) {
|
||||
$this->searchCache[$cachekey] = SphinxSearch::search('DocumentationPage', $keywords, array_merge_recursive(array(
|
||||
'start' => $start,
|
||||
'pagesize' => $this->pageLength
|
||||
)));
|
||||
}
|
||||
|
||||
$results = $this->searchCache[$cachekey];
|
||||
}
|
||||
|
||||
return array(
|
||||
'Query' => DBField::create('Text', $keywords),
|
||||
'Results' => $results
|
||||
);
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ class DocumentationViewer extends Controller {
|
||||
'LanguageForm',
|
||||
'doLanguageForm',
|
||||
'handleRequest',
|
||||
'DocumentationSearchForm'
|
||||
);
|
||||
|
||||
static $casting = array(
|
||||
@ -85,7 +86,10 @@ class DocumentationViewer extends Controller {
|
||||
* @return SS_HTTPResponse
|
||||
*/
|
||||
public function handleRequest(SS_HTTPRequest $request) {
|
||||
// Workaround for root routing, e.g. Director::addRules(10, array('$Action' => 'DocumentationViewer'))
|
||||
|
||||
// if we submitted a form, let that pass
|
||||
if($request->httpMethod() != "GET") return parent::handleRequest($request);
|
||||
|
||||
$this->Version = ($request->param('Action')) ? $request->param('Action') : $request->shift();
|
||||
$this->Lang = $request->shift();
|
||||
$this->ModuleName = $request->shift();
|
||||
@ -140,10 +144,8 @@ class DocumentationViewer extends Controller {
|
||||
return $this->response;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return parent::handleRequest($request);
|
||||
}
|
||||
|
||||
@ -271,12 +273,12 @@ class DocumentationViewer extends Controller {
|
||||
$absFilepath = $module->getPath() . '/index.md';
|
||||
$relativeFilePath = str_replace($module->getPath(), '', $absFilepath);
|
||||
if(file_exists($absFilepath)) {
|
||||
$page = new DocumentationPage(
|
||||
$relativeFilePath,
|
||||
$module,
|
||||
$this->Lang,
|
||||
$this->Version
|
||||
);
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath($relativeFilePath);
|
||||
$page->setEntity($module);
|
||||
$page->setLang($this->Lang);
|
||||
$page->setVersion($this->Version);
|
||||
|
||||
$content = DocumentationParser::parse($page, $this->Link(array_slice($this->Remaining, -1, -1)));
|
||||
} else {
|
||||
$content = '';
|
||||
@ -317,12 +319,14 @@ class DocumentationViewer extends Controller {
|
||||
$absFilepath = DocumentationParser::find_page($module->getPath(), $this->Remaining);
|
||||
if($absFilepath) {
|
||||
$relativeFilePath = str_replace($module->getPath(), '', $absFilepath);
|
||||
return new DocumentationPage(
|
||||
$relativeFilePath,
|
||||
$module,
|
||||
$this->Lang,
|
||||
$this->Version
|
||||
);
|
||||
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath($relativeFilePath);
|
||||
$page->setEntity($module);
|
||||
$page->setLang($this->Lang);
|
||||
$page->setVersion($this->Version);
|
||||
|
||||
return $page;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -398,7 +402,9 @@ class DocumentationViewer extends Controller {
|
||||
* @return DataObjectSet
|
||||
*/
|
||||
function getBreadcrumbs() {
|
||||
$pages = array_merge(array($this->ModuleName), $this->Remaining);;
|
||||
if(!$this->Remaining) $this->Remaining = array();
|
||||
|
||||
$pages = array_merge(array($this->ModuleName), $this->Remaining);
|
||||
|
||||
$output = new DataObjectSet();
|
||||
|
||||
@ -509,4 +515,39 @@ class DocumentationViewer extends Controller {
|
||||
static function get_link_base() {
|
||||
return self::$link_base;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see {@link Form::FormObjectLink()}
|
||||
*/
|
||||
function FormObjectLink($name) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Documentation Basic Search Form
|
||||
*
|
||||
* Integrates with sphinx
|
||||
* @return Form
|
||||
*/
|
||||
function DocumentationSearchForm() {
|
||||
|
||||
$fields = new FieldSet(
|
||||
new TextField('Search')
|
||||
);
|
||||
|
||||
$actions = new FieldSet(
|
||||
new FormAction('doDocumentationSearchForm', 'Search')
|
||||
);
|
||||
|
||||
return new Form($this, 'DocumentationSearchForm', $fields, $actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Past straight to results, display and encode the query
|
||||
*/
|
||||
function doDocumentationSearchForm($data, $form) {
|
||||
$query = (isset($data['Search'])) ? urlencode($data['Search']) : "";
|
||||
|
||||
$this->redirect('DocumentationSearch/search/'. $query);
|
||||
}
|
||||
}
|
@ -2,31 +2,31 @@
|
||||
class DocumentationPageTest extends SapphireTest {
|
||||
|
||||
function testGetRelativePath() {
|
||||
$page = new DocumentationPage(
|
||||
'test.md',
|
||||
new DocumentationEntity('mymodule', null, BASE_PATH . '/sapphiredocs/tests/docs/')
|
||||
);
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath('test.md');
|
||||
$page->setEntity(new DocumentationEntity('mymodule', null, BASE_PATH . '/sapphiredocs/tests/docs/'));
|
||||
|
||||
$this->assertEquals('test.md', $page->getRelativePath());
|
||||
|
||||
$page = new DocumentationPage(
|
||||
'subfolder/subpage.md',
|
||||
new DocumentationEntity('mymodule', null, BASE_PATH . '/sapphiredocs/tests/docs/')
|
||||
);
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath('subfolder/subpage.md');
|
||||
$page->setEntity(new DocumentationEntity('mymodule', null, BASE_PATH . '/sapphiredocs/tests/docs/'));
|
||||
|
||||
$this->assertEquals('subfolder/subpage.md', $page->getRelativePath());
|
||||
}
|
||||
|
||||
function testGetPath() {
|
||||
$absPath = BASE_PATH . '/sapphiredocs/tests/docs/';
|
||||
$page = new DocumentationPage(
|
||||
'test.md',
|
||||
new DocumentationEntity('mymodule', null, $absPath)
|
||||
);
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath('test.md');
|
||||
$page->setEntity(new DocumentationEntity('mymodule', null, $absPath));
|
||||
|
||||
$this->assertEquals($absPath . 'en/test.md', $page->getPath());
|
||||
|
||||
$page = new DocumentationPage(
|
||||
'subfolder/subpage.md',
|
||||
new DocumentationEntity('mymodule', null, $absPath)
|
||||
);
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath('subfolder/subpage.md');
|
||||
$page->setEntity(new DocumentationEntity('mymodule', null, $absPath));
|
||||
|
||||
$this->assertEquals($absPath . 'en/subfolder/subpage.md', $page->getPath());
|
||||
}
|
||||
|
||||
|
@ -24,12 +24,12 @@ class DocumentationParserTest extends SapphireTest {
|
||||
|
||||
function testImageRewrites() {
|
||||
// Page on toplevel
|
||||
$page = new DocumentationPage(
|
||||
'subfolder/subpage.md',
|
||||
new DocumentationEntity('mymodule', '2.4', BASE_PATH . '/sapphiredocs/tests/docs/'),
|
||||
'en',
|
||||
'2.4'
|
||||
);
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath('subfolder/subpage.md');
|
||||
$page->setEntity(new DocumentationEntity('mymodule', '2.4', BASE_PATH . '/sapphiredocs/tests/docs/'));
|
||||
$page->setLang('en');
|
||||
$page->setVersion('2.4');
|
||||
|
||||
$result = DocumentationParser::rewrite_image_links($page->getMarkdown(), $page, 'mycontroller/cms/2.4/en/');
|
||||
$this->assertContains(
|
||||
'[relative image link](' . Director::absoluteBaseURL() . '/sapphiredocs/tests/docs/en/subfolder/_images/image.png)',
|
||||
@ -48,12 +48,13 @@ class DocumentationParserTest extends SapphireTest {
|
||||
|
||||
function testApiLinks() {
|
||||
// Page on toplevel
|
||||
$page = new DocumentationPage(
|
||||
'test.md',
|
||||
new DocumentationEntity('mymodule', '2.4', BASE_PATH . '/sapphiredocs/tests/docs/'),
|
||||
'en',
|
||||
'2.4'
|
||||
);
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath('test.md');
|
||||
$page->setEntity(new DocumentationEntity('mymodule', '2.4', BASE_PATH . '/sapphiredocs/tests/docs/'));
|
||||
$page->setLang('en');
|
||||
$page->setVersion('2.4');
|
||||
|
||||
|
||||
$result = DocumentationParser::rewrite_api_links($page->getMarkdown(), $page, 'mycontroller/cms/2.4/en/');
|
||||
$this->assertContains(
|
||||
'[link: api](http://api.silverstripe.org/search/lookup/?q=DataObject&version=2.4&module=mymodule)',
|
||||
@ -65,12 +66,11 @@ class DocumentationParserTest extends SapphireTest {
|
||||
}
|
||||
|
||||
function testHeadlineAnchors() {
|
||||
$page = new DocumentationPage(
|
||||
'test.md',
|
||||
new DocumentationEntity('mymodule', '2.4', BASE_PATH . '/sapphiredocs/tests/docs/'),
|
||||
'en',
|
||||
'2.4'
|
||||
);
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath('test.md');
|
||||
$page->setEntity(new DocumentationEntity('mymodule', '2.4', BASE_PATH . '/sapphiredocs/tests/docs/'));
|
||||
$page->setLang('en');
|
||||
$page->setVersion('2.4');
|
||||
|
||||
$result = DocumentationParser::rewrite_heading_anchors($page->getMarkdown(), $page);
|
||||
|
||||
@ -104,11 +104,12 @@ class DocumentationParserTest extends SapphireTest {
|
||||
|
||||
function testRelativeLinks() {
|
||||
// Page on toplevel
|
||||
$page = new DocumentationPage(
|
||||
'test.md',
|
||||
new DocumentationEntity('mymodule', null, BASE_PATH . '/sapphiredocs/tests/docs/')
|
||||
);
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath('test.md');
|
||||
$page->setEntity(new DocumentationEntity('mymodule', '2.4', BASE_PATH . '/sapphiredocs/tests/docs/'));
|
||||
|
||||
$result = DocumentationParser::rewrite_relative_links($page->getMarkdown(), $page, 'mycontroller/cms/2.4/en/');
|
||||
|
||||
$this->assertContains(
|
||||
'[link: subfolder index](mycontroller/cms/2.4/en/subfolder/)',
|
||||
$result
|
||||
@ -127,11 +128,12 @@ class DocumentationParserTest extends SapphireTest {
|
||||
);
|
||||
|
||||
// Page in subfolder
|
||||
$page = new DocumentationPage(
|
||||
'subfolder/subpage.md',
|
||||
new DocumentationEntity('mymodule', null, BASE_PATH . '/sapphiredocs/tests/docs/')
|
||||
);
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath('subfolder/subpage.md');
|
||||
$page->setEntity(new DocumentationEntity('mymodule', '2.4', BASE_PATH . '/sapphiredocs/tests/docs/'));
|
||||
|
||||
$result = DocumentationParser::rewrite_relative_links($page->getMarkdown(), $page, 'mycontroller/cms/2.4/en/');
|
||||
|
||||
$this->assertContains(
|
||||
'[link: absolute index](mycontroller/cms/2.4/en/)',
|
||||
$result
|
||||
@ -154,11 +156,12 @@ class DocumentationParserTest extends SapphireTest {
|
||||
);
|
||||
|
||||
// Page in nested subfolder
|
||||
$page = new DocumentationPage(
|
||||
'subfolder/subsubfolder/subsubpage.md',
|
||||
new DocumentationEntity('mymodule', null, BASE_PATH . '/sapphiredocs/tests/docs/')
|
||||
);
|
||||
$page = new DocumentationPage();
|
||||
$page->setRelativePath('subfolder/subsubfolder/subsubpage.md');
|
||||
$page->setEntity(new DocumentationEntity('mymodule', '2.4', BASE_PATH . '/sapphiredocs/tests/docs/'));
|
||||
|
||||
$result = DocumentationParser::rewrite_relative_links($page->getMarkdown(), $page, 'mycontroller/cms/2.4/en/');
|
||||
|
||||
$this->assertContains(
|
||||
'[link: absolute index](mycontroller/cms/2.4/en/)',
|
||||
$result
|
||||
|
Loading…
Reference in New Issue
Block a user