APICHANGE: rather than passing the structure through the constructor, do so via setters which will allow us more flexibility

This commit is contained in:
Will Rossiter 2010-10-21 20:27:23 +00:00
parent ac5ce3872e
commit d2eb92233e
6 changed files with 217 additions and 102 deletions

View File

@ -1,4 +1,5 @@
<?php
/**
* A specific page within a {@link DocumentationEntity}.
* Has to represent an actual file, please use {@link DocumentationViewer}
@ -18,33 +19,26 @@ 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
*/
function getEntity() {
return $this->entity;
}
function setEntity($entity) {
$this->entity = $entity;
}
/**
* @return String Relative path to file or folder within the entity (including file extension),
@ -54,23 +48,44 @@ 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);
}
}

View File

@ -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) {
@ -435,7 +438,7 @@ class DocumentationParser {
}
}
closedir($handle);
return $pages;

View File

@ -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,21 +90,60 @@ class DocumentationSearch extends Controller {
if($modules) {
foreach($modules as $module) {
foreach($module->getLanguages() as $language) {
$pages = DocumentationParser::get_pages_from_folder($module->getPath(false, $language));
try {
$pages = DocumentationParser::get_pages_from_folder($module->getPath(false, $language));
if($pages) {
foreach($pages as $page) {
$output->push(new ArrayData(array(
'Title' => $page->Title,
'Content' => file_get_contents($page->Path),
'ID' => base_convert(substr(md5($page->Path), -8), 16, 10)
)));
if($pages) {
foreach($pages as $page) {
$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
);
}
}

View File

@ -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();
@ -139,10 +143,8 @@ class DocumentationViewer extends Controller {
$this->redirect($link, 301); // permanent redirect
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);
}
}

View File

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

View File

@ -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