/** * This expects to find: * {{#topic:Text Name}} * * @param Parser $parser * @param string $param1 Full text name of topic, must be converted to wiki topic name. * @return array * * TODO: Much of this function duplicates code above in efGetTitleFromMarkup(), can we DRY? * There really shouldn't be any real code in this file, just calls to class methods... */ function efTopicParserFunction_Render(&$parser, $param1 = '') { global $wgArticlePath, $wgTitle, $action; if (PonyDocsExtension::isSpeedProcessingEnabled()) { return TRUE; } /** * We ignore this parser function if not in a TOC management page. */ if (!preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(.*):(.*)TOC(.*)/i', $wgTitle->__toString(), $matches)) { return FALSE; } $manualShortName = $matches[2]; $productShortName = $matches[1]; PonyDocsWiki::getInstance($productShortName); /** * Get the earliest tagged version of this TOC page and append it to the wiki page? * Ensure the manual is valid then use PonyDocsManual::getManualByShortName(). * Next attempt to get the version tags for this page -- which may be NONE -- * and from this determine the "earliest" version to which this page applies. * * TODO: This comment is duplicated above in efGetTitleFromMarkup, can we DRY? */ if (!PonyDocsProductManual::IsManual($productShortName, $manualShortName)) { return FALSE; } $pManual = PonyDocsProductManual::GetManualByShortName($productShortName, $manualShortName); $pTopic = new PonyDocsTopic(new Article($wgTitle)); /** * @FIXME: If TOC page is NOT tagged with any versions we cannot create the pages/links to the * topics, right? */ $manVersionList = $pTopic->getProductVersions(); if (!sizeof($manVersionList)) { return $parser->insertStripItem($param1, $parser->mStripState); } $earliestVersion = PonyDocsProductVersion::findEarliest($productShortName, $manVersionList); /** * Clean up the full text name into a wiki-form. This means remove spaces, #, ?, and a few other * characters which are not valid or wanted. It's not important HOW this is done as long as it is * consistent. */ $wikiTopic = preg_replace('/([^' . str_replace(' ', '', Title::legalChars()) . '])/', '', $param1); $wikiPath = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $productShortName . ':' . $manualShortName . ':' . $wikiTopic; $dbr = wfGetDB(DB_SLAVE); /** * Now look in the database for any instance of this topic name PLUS :<version>. * We need to look in categorylinks for it to find a record with a cl_to (version tag) * which is equal to the set of the versions for this TOC page. * For instance, if the TOC page was for versions 1.0 and 1.1 and our topic was 'How To Foo' * we need to find any cl_sortkey which is 'HowToFoo:%' and has a cl_to equal to 1.0 or 1.1. * There should only be 0 or 1, so we ignore anything beyond 1. * If found, we use THAT cl_sortkey as the link; * if NOT found we create a new topic, the name being the compressed topic name plus the earliest TOC version * ($earliestVersion->getName()). * We then need to ACTUALLY create it in the database, tag it with all the versions the TOC mgmt page is tagged with, * and set the H1 to the text inside the parser function. * * @fixme: Can we test if $action=save here so we don't do this on every page view? */ $versionIn = array(); foreach ($manVersionList as $pV) { $versionIn[] = $productShortName . ':' . $pV->getVersionName(); } $res = $dbr->select(array('categorylinks', 'page'), 'page_title', array('cl_from = page_id', 'page_namespace = "' . NS_PONYDOCS . '"', "cl_to IN ('V:" . implode("','V:", $versionIn) . "')", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper($productShortName . ':' . $manualShortName . ':' . $wikiTopic)) . ":%'"), __METHOD__); $topicName = ''; if (!$res->numRows()) { /** * No match -- so this is a "new" topic. Set name. */ $topicName = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $productShortName . ':' . $manualShortName . ':' . $wikiTopic . ':' . $earliestVersion->getVersionName(); } else { $row = $dbr->fetchObject($res); $topicName = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$row->page_title}"; } $output = '<a href="' . wfUrlencode(str_replace('$1', $topicName, $wgArticlePath)) . '">' . $param1 . '</a>'; return $parser->insertStripItem($output, $parser->mStripState); }
/** * Updates or deletes Doc Links for the article being passed in. * @param string $updateOrDelete possible values: "update" or "delete" * @param Article $article the article to be updated or deleted * @param string $content content of the article to be updated or deleted */ public static function updateOrDeleteDocLinks($updateOrDelete, $article, $content = NULL) { $dbh = wfGetDB(DB_MASTER); if ($updateOrDelete == "update") { // Match all links in the article /* Breakdown of the regex below: * two left brackets * followed by zero or more misc chars ($match[1]), until * a pound followed by one or more misc chars ($match[2]) -- but this section is optional * followed by an optional | * followed by zero or more misc chars ($match[4]) ($match[3] is the misc chars plus the |) * followed by two right brackets * Things that would match: * [[TextHere:OtherTextHere#MoreText|StillMoreText]] * [[TextHere:MoreText:Text:Text|StillMoreText]] * [[TextHere:MoreText:Text:Text:Text|StillMoreText]] * [[TextHere:OtherTextHere|StillMoreText]] * [[TextHereStillMoreText]] * etc. * For PonyDocs, this maps to: * [[Topic]] * [[Documentation:Product:Manual:Topic]] * [[Documentation:Product:Manual:Topic:Version]] * [[OtherNamespace:Topic]] */ // TODO we really should refactor this regex; for now, leaving intact $regex = "/\\[\\[([A-Za-z0-9,:._ -]*)(\\#[A-Za-z0-9 _-]+)?([|]?([A-Za-z0-9,:.'_?!@\\/\"()#\$ -]*))\\]\\]/"; preg_match_all($regex, $content, $matches, PREG_SET_ORDER); } // Get the title of the article $title = $article->getTitle()->getFullText(); $titlePieces = explode(':', $title); $fromNamespace = $titlePieces[0]; $toAndFromLinksToInsert = array(); $fromLinksToDelete = array(); // $titlePieces[3] is the version // if this is not set, we're not looking at a Topic (probably we're looking at a TOC) and we don't need doclinks if ($fromNamespace == PONYDOCS_DOCUMENTATION_NAMESPACE_NAME && isset($titlePieces[3])) { // TODO only process this topic if it's not a TOC. // Do PonyDocs-specific stuff (loop through all inherited versions) // Get the versions associated with this topic $topic = new PonyDocsTopic($article); PonyDocsProductVersion::LoadVersionsForProduct($titlePieces[1], true, true); $ponydocsVersions = $topic->getProductVersions(); // Add a link to the database for each version foreach ($ponydocsVersions as $ver) { // Make a pretty PonyDocs URL (with slashes) out of the mediawiki title (with colons) // Put this $ver in the version spot. We want one URL per inherited version $titleNoVersion = $fromNamespace . ":" . $titlePieces[1] . ":" . $titlePieces[2] . ":" . $titlePieces[3]; $humanReadableTitle = self::translateTopicTitleForDocLinks($titleNoVersion, $fromNamespace, $ver, $topic); // this will add the version // Add this title to the array of titles to be deleted from the database $fromLinksToDelete[] = $humanReadableTitle; if ($updateOrDelete == "update") { // Add links in article to database foreach ($matches as $match) { // Get pretty to_link $toUrl = self::translateTopicTitleForDocLinks($match[1], $fromNamespace, $ver, $topic); // Add this from_link and to_link to array to be inserted into the database if ($toUrl) { $toAndFromLinksToInsert[] = array('from_link' => $humanReadableTitle, 'to_link' => $toUrl); } } } } } elseif ($fromNamespace != PONYDOCS_DOCUMENTATION_NAMESPACE_NAME) { // Do generic mediawiki stuff for non-PonyDocs namespaces // Add this title to the array of titles to be deleted from the database // We don't need to translate title here since we're not in the PonyDocs namespace $fromLinksToDelete[] = $title; if ($updateOrDelete == "update") { // Add links in article to database foreach ($matches as $match) { // Get pretty to_link $toUrl = self::translateTopicTitleForDocLinks($match[1]); // Add this from_link and to_link to array to be inserted into the database if ($toUrl) { $toAndFromLinksToInsert[] = array('from_link' => $title, 'to_link' => $toUrl); } } } } // Perform database queries using arrays populated above // First, delete to clear old data out of the database if (!empty($fromLinksToDelete)) { foreach ($fromLinksToDelete as &$fromLinkToDelete) { $fromLinkToDelete = $dbh->strencode($fromLinkToDelete); } $deleteWhereConds = implode("' OR from_link = '", $fromLinksToDelete); $deleteQuery = "DELETE FROM ponydocs_doclinks WHERE from_link = '" . $deleteWhereConds . "'"; $dbh->query($deleteQuery); } // Now insert new data, if we have any if (!empty($toAndFromLinksToInsert)) { $insertValuesAry = array(); foreach ($toAndFromLinksToInsert as $toAndFromLink) { $insertValuesAry[] = "'" . $dbh->strencode($toAndFromLink['from_link']) . "', '" . $dbh->strencode($toAndFromLink['to_link']) . "'"; } $insertValuesString = implode("), (", $insertValuesAry); $insertQuery = "INSERT INTO ponydocs_doclinks (from_link, to_link) VALUES (" . $insertValuesString . ")"; $dbh->query($insertQuery); } return true; }
/** * Return a simple associative array format for template output of all versions which apply to the supplied topic. * * @param PonyDocsTopic $pTopic Topic to obtain versions for. * @return array */ public function getVersionsForTopic(PonyDocsTopic &$pTopic) { global $wgArticlePath; $versions = array(); foreach ($pTopic->getProductVersions() as $productVersion) { $versions[] = array('name' => $productVersion->getVersionName(), 'href' => str_replace('$1', 'Category:V:' . $productVersion->getProductName() . ':' . $productVersion->getVersionName(), $wgArticlePath)); } return $versions; }