ENHANCEMENT: use urls in the format module/lang/version rather than version first. Tweaks to the parser to prevent infinite loops

This commit is contained in:
Will Rossiter 2011-01-14 01:03:46 +00:00
parent 24f1b13233
commit fc8ab96c51
10 changed files with 87 additions and 66 deletions

View File

@ -16,6 +16,8 @@ Reads markdown documentation files from the /docs/ folder in . To read documenta
For more documentation on how to use the module please read /docs/Writing-Documentation.md
(or via this in /dev/docs/sapphiredocs/Writing-Documentation in your webbrowser)
**Note** This module assumes you are using numeric values for your versions.
## Syntax Highlighting ##
The custom Markdown parser can render custom prefixes for code blocks,
@ -58,4 +60,4 @@ To include the syntax highlighter source, add the following to your `Documentati
Requirements::css('sapphiredocs/thirdparty/syntaxhighlighter/styles/shThemeRDark.css');
You can overload the `DocumentationViewer` class and add a custom route through `Director::addRule()`
if you prefer not to modify the module file.>>>>>>> .r115400
if you prefer not to modify the module file.

View File

@ -238,9 +238,9 @@ class DocumentationEntity extends ViewableData {
return Controller::join_links(
Director::absoluteBaseURL(),
DocumentationViewer::get_link_base(),
$version,
$this->moduleFolder,
$lang,
$this->moduleFolder
$version
);
}

View File

@ -34,10 +34,11 @@ class DocumentationParser {
if(!$page || (!$page instanceof DocumentationPage)) return false;
$md = $page->getMarkdown();
// Pre-processing
$md = self::rewrite_image_links($md, $page);
$md = self::rewrite_relative_links($md, $page, $baselink);
$md = self::rewrite_api_links($md, $page);
$md = self::rewrite_heading_anchors($md, $page);
$md = self::rewrite_code_blocks($md, $page);
@ -103,6 +104,7 @@ class DocumentationParser {
// Don't process absolute links (based on protocol detection)
$urlParts = parse_url($url);
if($urlParts && isset($urlParts['scheme'])) continue;
// Rewrite URL (relative or absolute)
@ -246,6 +248,7 @@ class DocumentationParser {
* @return String Markdown
*/
static function rewrite_relative_links($md, $page, $baselink) {
$re = '/
([^\!]?) # exclude image format
\[
@ -262,6 +265,7 @@ class DocumentationParser {
if($relativePath == '.') $relativePath = '';
if($matches) {
foreach($matches[0] as $i => $match) {
$title = $matches[2][$i];
$url = $matches[3][$i];
@ -272,12 +276,12 @@ class DocumentationParser {
// Don't process absolute links (based on protocol detection)
$urlParts = parse_url($url);
if($urlParts && isset($urlParts['scheme'])) continue;
// Rewrite URL (relative or absolute)
if(preg_match('/^\//', $url)) {
$relativeUrl = $baselink . $url;
$relativeUrl = Controller::join_links($baselink, $url);
} else {
$relativeUrl = $baselink . '/' . $relativePath . '/' . $url;
$relativeUrl = Controller::join_links($baselink, $relativePath, $url);
}
// Resolve relative paths

View File

@ -232,13 +232,14 @@ class DocumentationService {
* @return DocumentationEntity $module the registered module
*/
public static function is_registered_module($module, $version = false, $lang = false) {
$check = ($module instanceof DocumentationEntity) ? $module->getModuleFolder() : (string) $module;
if(isset(self::$registered_modules[$check])) {
$module = self::$registered_modules[$check];
if($lang && !$module->hasLanguage($lang)) return false;
if($version && !$module->hasVersion($version)) return false;
if(($lang && !$module->hasLanguage($lang)) || ($version && !$module->hasVersion($version))) {
return false;
}
return $module;
}

View File

@ -25,7 +25,7 @@ class DocumentationViewer extends Controller {
/**
* @var string
*/
public $version = "current";
public $version = "";
/**
* @var string
@ -128,7 +128,6 @@ class DocumentationViewer extends Controller {
$thirdParam = $request->shift();
$this->Remaining = $request->shift(10);
DocumentationService::load_automatic_registration();
if(isset($firstParam)) {
@ -146,33 +145,34 @@ class DocumentationViewer extends Controller {
return $this->response;
}
else if(is_numeric($firstParam) || $firstParam == "current") {
// its a version number first in the form 2.4/en/sapphire
$this->version = $firstParam;
$this->lang = $secondParam;
$this->module = $thirdParam;
$this->module = $firstParam;
$this->lang = $secondParam;
if(isset($thirdParam) && (is_numeric($thirdParam))) {
$this->version = $thirdParam;
}
else {
// we have a language first in the form /en/sapphire
// current version so store one area para
array_unshift($this->Remaining, $thirdParam);
$this->lang = $firstParam;
$this->module = $secondParam;
$this->version = "";
}
}
// 'current' version mapping
$module = DocumentationService::is_registered_module($this->module, null, $this->getLang());
if($module && $this->getVersion()) {
if($module) {
$current = $module->getCurrentVersion();
$version = $this->getVersion();
if($version == 'current') {
if(!$version || $version == '') {
$this->version = $current;
} else if($current == $version) {
$this->version = 'current';
$this->version = '';
$link = $this->Link($this->Remaining);
$this->response = new SS_HTTPResponse();
@ -180,8 +180,7 @@ class DocumentationViewer extends Controller {
return $this->response;
}
}
}
return parent::handleRequest($request);
}
@ -216,7 +215,8 @@ class DocumentationViewer extends Controller {
}
/**
* Returns the current version
* Returns the current version. If no version is set then it is the current
* set version so need to pull that from the module
*
* @return String
*/
@ -369,9 +369,9 @@ class DocumentationViewer extends Controller {
*/
function getPage() {
$module = $this->getModule();
if(!$module) return false;
if(!$module) return false;
$absFilepath = DocumentationService::find_page($module, $this->Remaining);
if($absFilepath) {
@ -399,7 +399,7 @@ class DocumentationViewer extends Controller {
function getModulePages() {
if($module = $this->getModule()) {
$pages = DocumentationService::get_pages_from_folder($module, null, false);
if($pages) {
foreach($pages as $page) {
if(strtolower($page->Title) == "index") {
@ -479,7 +479,7 @@ class DocumentationViewer extends Controller {
if($page = $this->getPage()) {
// Remove last portion of path (filename), we want a link to the folder base
$html = DocumentationParser::parse($page, $this->Link(array_slice($this->Remaining, -1, -1)));
$html = DocumentationParser::parse($page, $this->Link(array_slice($this->Remaining, 0)));
return DBField::create("HTMLText", $html);
}
@ -563,7 +563,7 @@ class DocumentationViewer extends Controller {
}
}
$link = Controller::join_links($base, self::get_link_base(), $version, $lang, $module, $action);
$link = Controller::join_links($base, self::get_link_base(), $module, $lang, $version, $action);
return $link;
}

View File

@ -15,21 +15,21 @@ class DocumentationPageTest extends SapphireTest {
$page->setEntity($entity);
// single layer
$this->assertStringEndsWith('en/testmodule/test', $page->Link(), 'The page link should have no extension and have a language');
$this->assertStringEndsWith('testmodule/en/test', $page->Link(), 'The page link should have no extension and have a language');
$folder = new DocumentationPage();
$folder->setRelativePath('sort');
$folder->setEntity($entity);
// folder, should have a trailing slash
$this->assertStringEndsWith('en/testmodule/sort/', $folder->Link());
$this->assertStringEndsWith('testmodule/en/sort/', $folder->Link());
// second
$nested = new DocumentationPage();
$nested->setRelativePath('subfolder/subpage.md');
$nested->setEntity($entity);
$this->assertStringEndsWith('en/testmodule/subfolder/subpage', $nested->Link());
$this->assertStringEndsWith('testmodule/en/subfolder/subpage', $nested->Link());
// test with version.
$entity = DocumentationService::register("versionlinks", BASE_PATH . "/sapphiredocs/tests/docs-2/", '1');
@ -37,7 +37,7 @@ class DocumentationPageTest extends SapphireTest {
$page->setRelativePath('test.md');
$page->setEntity($entity);
$page->setVersion('1');
$this->assertStringEndsWith('1/en/versionlinks/test', $page->Link());
$this->assertStringEndsWith('versionlinks/en/1/test', $page->Link());
}

View File

@ -139,6 +139,10 @@ HTML;
'[link: api](api:DataObject)',
$result
);
$this->assertContains(
'[link: relative](mycontroller/cms/2.4/a-relative-file.md)',
$result
);
// Page in subfolder
$page = new DocumentationPage();
@ -147,6 +151,11 @@ HTML;
$result = DocumentationParser::rewrite_relative_links($page->getMarkdown(), $page, 'mycontroller/cms/2.4/en/');
$this->assertContains(
'[link: relative](mycontroller/cms/2.4/en/subfolder/subpage.md)',
$result
);
$this->assertContains(
'[link: absolute index](mycontroller/cms/2.4/en/)',
$result

View File

@ -41,7 +41,7 @@ class DocumentationViewerTest extends FunctionalTest {
function testGetModulePagesShort() {
$v = new DocumentationViewer();
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.4/en/DocumentationViewerTests/subfolder/'));
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.4/subfolder/'));
$pages = $v->getModulePages();
$arr = $pages->toArray();
@ -52,7 +52,7 @@ class DocumentationViewerTest extends FunctionalTest {
function testGetModulePages() {
$v = new DocumentationViewer();
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.4/en/DocumentationViewerTests/subfolder/'));
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.4/subfolder/'));
$pages = $v->getModulePages();
$this->assertEquals(
array('sort/', 'subfolder/', 'test.md'),
@ -69,9 +69,9 @@ class DocumentationViewerTest extends FunctionalTest {
$links = $pages->column('Link');
$this->assertStringEndsWith('2.4/en/DocumentationViewerTests/sort/', $links[0]);
$this->assertStringEndsWith('2.4/en/DocumentationViewerTests/subfolder/', $links[1]);
$this->assertStringEndsWith('2.4/en/DocumentationViewerTests/test', $links[2]);
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/sort/', $links[0]);
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/', $links[1]);
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/test', $links[2]);
// Children
$pagesArr = $pages->toArray();
@ -96,44 +96,44 @@ class DocumentationViewerTest extends FunctionalTest {
$child2Links = $children->column('Link');
$subpage = $children->First();
$this->assertStringEndsWith('2.4/en/DocumentationViewerTests/subfolder/subpage', $child2Links[0]);
$this->assertStringEndsWith('2.4/en/DocumentationViewerTests/subfolder/subsubfolder/', $child2Links[1]);
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/subpage', $child2Links[0]);
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/subsubfolder/', $child2Links[1]);
}
function testCurrentRedirection() {
$response = $this->get('dev/docs/3.0/en/DocumentationViewerTests/test');
$response = $this->get('dev/docs/DocumentationViewerTests/en/3.0/test');
$this->assertEquals(301, $response->getStatusCode());
$this->assertEquals(
Director::absoluteBaseURL() . 'dev/docs/current/en/DocumentationViewerTests/test/',
Director::absoluteBaseURL() . 'dev/docs/DocumentationViewerTests/en/test/',
$response->getHeader('Location'),
'Redirection to current on page'
);
$response = $this->get('dev/docs/3.0/en/DocumentationViewerTests/');
$response = $this->get('dev/docs/DocumentationViewerTests/en/3.0');
$this->assertEquals(301, $response->getStatusCode());
$this->assertEquals(
Director::absoluteBaseURL() . 'dev/docs/current/en/DocumentationViewerTests/',
Director::absoluteBaseURL() . 'dev/docs/DocumentationViewerTests/en/',
$response->getHeader('Location'),
'Redirection to current on index'
);
$response = $this->get('dev/docs/2.3/en/DocumentationViewerTests/');
$response = $this->get('dev/docs/DocumentationViewerTests/en/2.3');
$this->assertEquals(200, $response->getStatusCode(), 'No redirection on older versions');
}
function testUrlParsing() {
// Module index
$v = new DocumentationViewer();
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.3/en/DocumentationViewerTests/test'));
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.3/test'));
$this->assertEquals('2.3', $v->getVersion());
$this->assertEquals('en', $v->getLang());
$this->assertEquals('DocumentationViewerTests', $v->module);
$this->assertEquals(array('test'), $v->Remaining);
// Module index without version and language. Should pick up the defaults
$v2 = new DocumentationViewer();
$response = $v2->handleRequest(new SS_HTTPRequest('GET', 'en/DocumentationViewerTests/test'));
$response = $v2->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/test'));
$this->assertEquals('3.0', $v2->getVersion());
$this->assertEquals('en', $v2->getLang());
@ -143,7 +143,7 @@ class DocumentationViewerTest extends FunctionalTest {
// Overall index
$v = new DocumentationViewer();
$response = $v->handleRequest(new SS_HTTPRequest('GET', ''));
$this->assertEquals('current', $v->getVersion());
$this->assertEquals('', $v->getVersion());
$this->assertEquals('en', $v->getLang());
$this->assertEquals('', $v->module);
$this->assertEquals(array(), $v->Remaining);
@ -152,35 +152,35 @@ class DocumentationViewerTest extends FunctionalTest {
function testBreadcrumbs() {
// Module index
$v = new DocumentationViewer();
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.4/en/DocumentationViewerTests/'));
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.4'));
$crumbs = $v->getBreadcrumbs();
$this->assertEquals(1, $crumbs->Count());
$crumbLinks = $crumbs->column('Link');
$this->assertStringEndsWith('DocumentationViewerTests/', $crumbLinks[0]);
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/', $crumbLinks[0]);
// Subfolder index
$v = new DocumentationViewer();
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.4/en/DocumentationViewerTests/subfolder/'));
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.4/subfolder/'));
$crumbs = $v->getBreadcrumbs();
$this->assertEquals(2, $crumbs->Count());
$crumbLinks = $crumbs->column('Link');
$this->assertStringEndsWith('DocumentationViewerTests/', $crumbLinks[0]);
$this->assertStringEndsWith('DocumentationViewerTests/subfolder/', $crumbLinks[1]);
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/', $crumbLinks[0]);
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/', $crumbLinks[1]);
// Subfolder page
$v = new DocumentationViewer();
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.4/en/DocumentationViewerTests/subfolder/subpage'));
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.4/subfolder/subpage'));
$crumbs = $v->getBreadcrumbs();
$this->assertEquals(3, $crumbs->Count());
$crumbLinks = $crumbs->column('Link');
$this->assertStringEndsWith('DocumentationViewerTests/', $crumbLinks[0]);
$this->assertStringEndsWith('DocumentationViewerTests/subfolder/', $crumbLinks[1]);
$this->assertStringEndsWith('DocumentationViewerTests/subfolder/subpage/', $crumbLinks[2]);
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/', $crumbLinks[0]);
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/', $crumbLinks[1]);
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/subpage/', $crumbLinks[2]);
}
function testRouting() {
$response = $this->get('dev/docs/2.4/en/DocumentationViewerTests/test');
$response = $this->get('dev/docs/DocumentationViewerTests/en/2.4/test');
$this->assertEquals(200, $response->getStatusCode());
$this->assertContains('english test', $response->getBody(), 'Toplevel content page');
}

View File

@ -1,9 +1,12 @@
[link: absolute index](/)
[link: absolute index with name](/index)
[link: relative index](../)
[link: relative](../subfolder/subpage.md)
[link: relative multiline
](../subfolder/subpage.md)
[link: relative parent page](../test)
[link: absolute parent page](/test)
![relative image link](_images/image.png)
![parent image link](../_images/image.png)
![absolute image link](/_images/image.png)
![absolute image link](/_images/image.png)

View File

@ -9,6 +9,8 @@ test
[link: with anchor](/test#anchor)
[link: http](http://silverstripe.org)
[link: api](api:DataObject)
[link: relative](../a-relative-file.md)
[api:DataObject::$has_one]
:::php