function testGetLink()
 {
     $entity = new DocumentationEntity('testmodule', null, BASE_PATH . '/sapphiredocs/tests/docs/');
     $page = new DocumentationPage();
     $page->setRelativePath('test.md');
     $page->setEntity($entity);
     // single layer
     $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('testmodule/en/sort/', $folder->Link());
     // second
     $nested = new DocumentationPage();
     $nested->setRelativePath('subfolder/subpage.md');
     $nested->setEntity($entity);
     $this->assertStringEndsWith('testmodule/en/subfolder/subpage', $nested->Link());
     // test with version.
     $entity = DocumentationService::register("versionlinks", BASE_PATH . "/sapphiredocs/tests/docs-v2.4/", '1');
     $entity->addVersion('2', BASE_PATH . "/sapphiredocs/tests/docs-v3.0/");
     $entity->setStableVersion('2');
     $page = new DocumentationPage();
     $page->setRelativePath('test.md');
     $page->setEntity($entity);
     $page->setVersion('1');
     $this->assertStringEndsWith('versionlinks/en/1/test', $page->Link());
 }
 function testHeadlineAnchors()
 {
     $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);
     /*
     		# Heading one {#Heading-one}
     
     		# Heading with custom anchor {#custom-anchor} {#Heading-with-custom-anchor-custom-anchor}
     
     		## Heading two {#Heading-two}
     
     		### Heading three {#Heading-three}
     
     		## Heading duplicate {#Heading-duplicate}
     
     		## Heading duplicate {#Heading-duplicate-2}
     
     		## Heading duplicate {#Heading-duplicate-3}
     */
     $this->assertContains('# Heading one {#heading-one}', $result);
     $this->assertContains('# Heading with custom anchor {#custom-anchor}', $result);
     $this->assertNotContains('# Heading with custom anchor {#custom-anchor} {#heading', $result);
     $this->assertContains('# Heading two {#heading-two}', $result);
     $this->assertContains('# Heading three {#heading-three}', $result);
     $this->assertContains('## Heading duplicate {#heading-duplicate}', $result);
     $this->assertContains('## Heading duplicate {#heading-duplicate-2}', $result);
     $this->assertContains('## Heading duplicate {#heading-duplicate-3}', $result);
 }
 /**
  * Return the summary / index text for this entity. Either pulled
  * from an index file or some other summary field
  *
  * @return DocumentationPage
  */
 function getIndexPage($version, $lang = 'en')
 {
     $path = $this->getPath($version, $lang);
     $absFilepath = Controller::join_links($path, 'index.md');
     if (file_exists($absFilepath)) {
         $relativeFilePath = str_replace($path, '', $absFilepath);
         $page = new DocumentationPage();
         $page->setRelativePath($relativeFilePath);
         $page->setEntity($this);
         $page->setLang($lang);
         $page->setVersion($version);
         return $page;
     }
     return false;
 }
 /**
  * Return the children from a given entity sorted by Title using natural ordering. 
  * It is used for building the tree of the page.
  *
  * @param DocumentationEntity path
  * @param string - an optional path within a entity
  * @param bool enable several recursive calls (more than 1 level)
  * @param string - version to use
  * @param string - lang to use
  *
  * @throws Exception
  * @return DataObjectSet
  */
 public static function get_pages_from_folder($entity, $relativePath = false, $recursive = true, $version = 'trunk', $lang = 'en')
 {
     $output = new DataObjectSet();
     $pages = array();
     if (!$entity instanceof DocumentationEntity) {
         user_error("get_pages_from_folder must be passed a entity", E_USER_ERROR);
     }
     $path = $entity->getPath($version, $lang);
     if (self::is_registered_entity($entity)) {
         self::get_pages_from_folder_recursive($path, $relativePath, $recursive, $pages);
     } else {
         return user_error("{$entity} is not registered", E_USER_WARNING);
     }
     if (count($pages) > 0) {
         natsort($pages);
         foreach ($pages as $key => $pagePath) {
             // get file name from the path
             $file = ($pos = strrpos($pagePath, '/')) ? substr($pagePath, $pos + 1) : $pagePath;
             $page = new DocumentationPage();
             $page->setTitle(self::clean_page_name($file));
             $relative = str_replace($path, '', $pagePath);
             // if no extension, put a slash on it
             if (strpos($relative, '.') === false) {
                 $relative .= '/';
             }
             $page->setEntity($entity);
             $page->setRelativePath($relative);
             $page->setVersion($version);
             $page->setLang($lang);
             $output->push($page);
         }
     }
     return $output;
 }
 /**
  * @return DocumentationPage
  */
 function getPage()
 {
     $entity = $this->getEntity();
     if (!$entity) {
         return false;
     }
     $version = $this->getVersion();
     $lang = $this->getLang();
     $absFilepath = DocumentationService::find_page($entity, $this->Remaining, $version, $lang);
     if ($absFilepath) {
         $relativeFilePath = str_replace($entity->getPath($version, $lang), '', $absFilepath);
         $page = new DocumentationPage();
         $page->setRelativePath($relativeFilePath);
         $page->setEntity($entity);
         $page->setLang($lang);
         $page->setVersion($version);
         return $page;
     }
     return false;
 }