filename = $filename; $this->path = $path; $this->entity = $entity; } /** * @return string */ public function getExtension() { return DocumentationHelper::get_extension($this->filename); } /** * @param string - has to be plain text for open search compatibility. * * @return string */ public function getBreadcrumbTitle($divider = ' - ') { $pathParts = explode('/', trim($this->getRelativePath(), '/')); // from the page from this array_pop($pathParts); // add the module to the breadcrumb trail. $pathParts[] = $this->entity->getTitle(); $titleParts = array_map( array( 'DocumentationHelper', 'clean_page_name' ), $pathParts ); $titleParts = array_filter( $titleParts, function ($val) { if ($val) { return $val; } } ); if ($this->getTitle()) { array_unshift($titleParts, $this->getTitle()); } return implode($divider, $titleParts); } /** * @return DocumentationEntity */ public function getEntity() { return $this->entity; } /** * @return string */ public function getTitle() { if ($this->title) { return $this->title; } $page = DocumentationHelper::clean_page_name($this->filename); if ($page == 'Index') { return $this->getTitleFromFolder(); } return $page; } public function getTitleFromFolder() { $folder = $this->getPath(); $entity = $this->getEntity()->getPath(); $folder = str_replace('index.md', '', $folder); // if it's the root of the entity then we want to use the entity name // otherwise we'll get 'En' for the entity folder if ($folder == $entity) { return $this->getEntity()->getTitle(); } else { $path = explode('/', trim($folder, '/')); $folderName = array_pop($path); } return DocumentationHelper::clean_page_name($folderName); } /** * @return string */ public function getSummary() { return $this->summary; } /** * Return the raw markdown for a given documentation page. * * @param boolean $removeMetaData * * @return string|false */ public function getMarkdown($removeMetaData = false) { try { if (is_file($this->getPath()) && $md = file_get_contents($this->getPath())) { $this->populateMetaDataFromText($md, $removeMetaData); return $md; } $this->read = true; } catch (InvalidArgumentException $e) { } return false; } /** * @return string */ public function getIntroduction() { if (!$this->read) { $this->getMarkdown(); } return $this->introduction; } /** * Parse a file and return the parsed HTML version. * * @param string $baselink * * @return string */ public function getHTML() { $html = DocumentationParser::parse( $this, $this->entity->Link() ); return $html; } /** * This should return the link from the entity root to the page. The link * value has the cleaned version of the folder names. See * {@link getRelativePath()} for the actual file path. * * @return string */ public function getRelativeLink() { $path = $this->getRelativePath(); $url = explode('/', $path); $url = implode( '/', array_map( function ($a) { return DocumentationHelper::clean_page_url($a); }, $url ) ); $url = trim($url, '/') . '/'; return $url; } /** * This should return the link from the entity root to the page. For the url * polished version, see {@link getRelativeLink()}. * * @return string */ public function getRelativePath() { return str_replace($this->entity->getPath(), '', $this->getPath()); } /** * @return string */ public function getPath() { return $this->path; } /** * Returns the URL that will be required for the user to hit to view the * given document base name. * * @param boolean $short If true, will attempt to return a short version of the url * This might omit the version number if this is the default version. * @return string */ public function Link($short = false) { return Controller::join_links( $this->entity->Link($short), $this->getRelativeLink() ); } /** * Determine and set the canonical URL for the given record, for example: dev/docs/en/Path/To/Document */ public function populateCanonicalUrl() { $url = Director::absoluteURL(Controller::join_links( Config::inst()->get('DocumentationViewer', 'link_base'), $this->getEntity()->getLanguage(), $this->getRelativeLink() )); $this->setCanonicalUrl($url); } /** * Return metadata from the first html block in the page, then remove the * block on request * * @param DocumentationPage $md * @param bool $remove */ public function populateMetaDataFromText(&$md, $removeMetaData = false) { if (!$md) { return; } // See if there is YAML metadata block at the top of the document. e.g. // --- // property: value // another: value // --- // // If we found one, then we'll use a YAML parser to extract the // data out and then remove the whole block from the markdown string. $parser = new \Mni\FrontYAML\Parser(); $document = $parser->parse($md, false); $yaml = $document->getYAML(); if ($yaml) { foreach ($yaml as $key => $value) { if (!property_exists(get_class($this), $key)) { continue; } $this->$key = $value; } if ($removeMetaData) { $md = $document->getContent(); } return; } // this is the alternative way of parsing the properties out that don't contain // a YAML block declared with --- // // get the text up to the first empty line $extPattern = "/^(.+)\n\r*\n/Uis"; $matches = preg_match($extPattern, $md, $block); if ($matches && $block[1]) { $metaDataFound = false; // find the key/value pairs $lines = preg_split('/\v+/', $block[1]); $key = ''; $value = ''; foreach ($lines as $line) { if (strpos($line, ':') !== false) { list($key, $value) = explode(':', $line, 2); $key = trim($key); $value = trim($value); } else { $value .= ' ' . trim($line); } if (property_exists(get_class(), $key)) { $this->$key = $value; $metaDataFound = true; } } // optionally remove the metadata block (only on the page that // is displayed) if ($metaDataFound && $removeMetaData) { $md = preg_replace($extPattern, '', $md); } } } public function getVersion() { return $this->entity->getVersion(); } /** * @return string */ public function __toString() { return sprintf(get_class($this) .': %s)', $this->getPath()); } /** * Set the canonical URL to use for this page * * @param string $canonicalUrl * @return $this */ public function setCanonicalUrl($canonicalUrl) { $this->canonicalUrl = $canonicalUrl; return $this; } /** * Get the canonical URL to use for this page. Will trigger discovery * via {@link DocumentationPage::populateCanonicalUrl()} if none is already set. * * @return string */ public function getCanonicalUrl() { if (!$this->canonicalUrl) { $this->populateCanonicalUrl(); } return $this->canonicalUrl; } }