public static function onArticleFromTitle_New(&$title, &$article) { global $wgScriptPath; global $wgArticlePath, $wgTitle, $wgOut, $wgHooks; $dbr = wfGetDB(DB_SLAVE); /** * We only care about Documentation namespace for rewrites and they must contain a slash, so scan for it. * $matches[1] = product * $matches[2] = latest|version * $matches[3] = manual * $matches[4] = topic */ if (!preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '\\/([' . PONYDOCS_PRODUCT_LEGALCHARS . ']*)\\/(.*)\\/(.*)\\/(.*)$/i', $title->__toString(), $matches)) { return false; } $defaultRedirect = PonyDocsExtension::getDefaultUrl(); /** * At this point $matches contains: * 0= Full title. * 1= Product name * 2= Version OR 'latest' as a string. * 3= Manual name (short name). * 4= Wiki topic name. */ $productName = $matches[1]; $versionName = $matches[2]; $manualName = $matches[3]; $topicName = $matches[4]; $product = PonyDocsProduct::GetProductByShortName($productName); // If we don't have a valid product, display 404 if (!$product instanceof PonyDocsProduct) { $wgHooks['BeforePageDisplay'][] = "PonyDocsExtension::handle404"; return false; } // If this article doesn't have a valid manual, don't display the article if (!PonyDocsProductManual::IsManual($productName, $manualName)) { $wgHooks['BeforePageDisplay'][] = "PonyDocsExtension::handle404"; return false; } // If this is a static product return because that should be handled by another function if ($product->isStatic()) { return true; } $versionSelectedName = PonyDocsProductVersion::GetSelectedVersion($productName); $version = ''; PonyDocsProductVersion::LoadVersionsForProduct($productName); if (!strcasecmp('latest', $versionName)) { /** * This will be a DESCENDING mapping of version name to PonyDocsVersion object and will ONLY contain the * versions available to the current user (i.e. LoadVersions() only loads the ones permitted). */ $releasedVersions = PonyDocsProductVersion::GetReleasedVersions($productName, true); if (empty($releasedVersions)) { return false; } $versionList = array_reverse($releasedVersions); $versionNameList = array(); foreach ($versionList as $pV) { $versionNameList[] = $pV->getVersionName(); } /** * Now get a list of version names to which the current topic is mapped in DESCENDING order as well * from the 'categorylinks' table. * * DB can't do descending order here, it depends on the order defined in versions page! So we have to * do some magic sorting below. */ $res = $dbr->select('categorylinks', 'cl_to', array('cl_to LIKE "V:%:%"', 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper("{$productName}:{$manualName}:{$topicName}")) . ":%'"), __METHOD__); if (!$res->numRows()) { /** * What happened here is we requested a topic that does not exist or is not linked to any version. * Perhaps setup a default redirect, Main_Page or something? */ if (PONYDOCS_DEBUG) { error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$defaultRedirect}"); } header("Location: " . $defaultRedirect); exit(0); } /** * Based on our list, get the PonyDocsVersion for each version tag and store in an array. Then pass this array * to our custom sort function via usort() -- the ending result is a sorted list in $existingVersions, with the * LATEST version at the front. * * @FIXME: GetVersionByName is missing some versions? */ $existingVersions = array(); while ($row = $dbr->fetchObject($res)) { if (preg_match('/^V:(.*):(.*)/i', $row->cl_to, $vmatch)) { $pVersion = PonyDocsProductVersion::GetVersionByName($vmatch[1], $vmatch[2]); if ($pVersion && !in_array($pVersion, $existingVersions)) { $existingVersions[] = $pVersion; } } } usort($existingVersions, "PonyDocs_ProductVersionCmp"); $existingVersions = array_reverse($existingVersions); // Okay, iterate through existingVersions. If we can't see that // any of them belong to our latest released version, redirect to // our latest handler. $latestReleasedVersion = PonyDocsProductVersion::GetLatestReleasedVersion($productName)->getVersionName(); $found = false; foreach ($existingVersions as $docVersion) { if ($docVersion->getVersionName() == $latestReleasedVersion) { $found = true; break; } } if (!$found) { if (PONYDOCS_DEBUG) { error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$wgScriptPath}/Special:PonyDocsLatestDoc?t={$title}"); } header("Location: " . $wgScriptPath . "/Special:SpecialLatestDoc?t={$title}", true, 302); exit(0); } /** * Now we need to filter out any versions which this user has no access to. The easiest way is to loop through * our resulting $existingVersions and see if each is in_array( $versionNameList ); if its NOT, continue looping. * Once we hit one, redirect. if we exhaust our list, go to the main page or something. */ foreach ($existingVersions as $pV) { if (in_array($pV->getVersionName(), $versionNameList)) { /** * Look up topic name and redirect to URL. */ $res = $dbr->select(array('categorylinks', 'page'), 'page_title', array('cl_from = page_id', 'page_namespace = "' . NS_PONYDOCS . '"', "cl_to = 'V:" . $dbr->strencode($pV->getProductName() . ':' . $pV->getVersionName()) . "'", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper("{$productName}:{$manualName}:{$topicName}")) . ":%'"), __METHOD__); if (!$res->numRows()) { if (PONYDOCS_DEBUG) { error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$defaultRedirect}"); } header("Location: " . $defaultRedirect); exit(0); } $row = $dbr->fetchObject($res); $title = Title::newFromText(PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$row->page_title}"); $article = new Article($title); $article->loadContent(); PonyDocsProductVersion::SetSelectedVersion($pV->getProductName(), $pV->getVersionName()); if (!$article->exists()) { $article = NULL; } else { // Without this we lose SplunkComments and version switcher. // Probably we can replace with a RequestContext in the future... $wgTitle = $title; } return TRUE; } } /** * Invalid redirect -- go to Main_Page or something. */ if (PONYDOCS_DEBUG) { error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$defaultRedirect}"); } header("Location: " . $defaultRedirect); exit(0); } else { /** * Ensure version specified in aliased URL is a valid version -- if it is not we just need to do our default * redirect here. */ $version = PonyDocsProductVersion::GetVersionByName($productName, $versionName); if (!$version) { if (PONYDOCS_DEBUG) { error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] unable to retrieve version ({$versionName}) for product ({$productName}); redirecting to {$defaultRedirect}"); } header("Location: " . $defaultRedirect); exit(0); } /** * Look up the TOPIC in the categorylinks and find the one which is tagged with the version supplied. This * is the URL to redirect to. */ $res = $dbr->select(array('categorylinks', 'page'), 'page_title', array('cl_from = page_id', 'page_namespace = "' . NS_PONYDOCS . '"', "cl_to = 'V:" . $dbr->strencode($productName . ':' . $versionSelectedName) . "'", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper("{$productName}:{$manualName}:{$topicName}")) . ":%'"), __METHOD__); if (!$res->numRows()) { /** * Handle invalid redirects? */ $wgHooks['BeforePageDisplay'][] = "PonyDocsExtension::handle404"; return false; } $row = $dbr->fetchObject($res); $title = Title::newFromText(PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$row->page_title}"); /// FIXME this shouldn't be necessary because selected version already comes from here PonyDocsProductVersion::SetSelectedVersion($productName, $versionSelectedName); $article = new Article($title); $article->loadContent(); if (!$article->exists()) { $article = NULL; } else { // Without this we lose SplunkComments and version switcher. // Probably we can replace with a RequestContext in the future... $wgTitle = $title; } return TRUE; } return FALSE; }
/** * This function returns information about the versions on this topic. * - Version permissions: unreleased, preview, or released * - Version age: older, latest, or newer * Since a Topic can have multiple versions, it's possible for a single topic to be in unreleased, preview, released, older, * latest, AND newer versions AT THE SAME TIME! * This information can be used by skins to change UI based on the version features. * * @return array */ public function getVersionClasses() { $productName = PonyDocsProduct::getSelectedProduct(); $versionClasses = array(); $releasedVersions = PonyDocsProductVersion::GetReleasedVersions($productName); // Just the names of our released versions $releasedNames = array(); foreach ($releasedVersions as $ver) { $releasedNames[] = strtolower($ver->getVersionName()); } $previewVersions = PonyDocsProductVersion::GetPreviewVersions($productName); // Just the names of our preview versions $previewNames = array(); foreach ($previewVersions as $ver) { $previewNames[] = strtolower($ver->getVersionName()); } $latestVersion = PonyDocsProductVersion::GetLatestReleasedVersion($productName); foreach ($this->versions as $version) { $versionName = strtolower($version->getVersionName()); // Is this version released, preview, or unreleased? if (in_array($versionName, $releasedNames)) { $versionClasses['released'] = TRUE; } elseif (in_array($versionName, $previewNames)) { $versionClasses['preview'] = TRUE; } else { $versionClasses['unreleased'] = TRUE; } // Is this version older or later or equal to the current version? if ($latestVersion) { if (PonyDocs_ProductVersionCmp($version, $latestVersion) < 0) { $versionClasses['older'] = TRUE; } elseif (PonyDocs_ProductVersionCmp($version, $latestVersion) > 0) { $versionClasses['newer'] = TRUE; } else { $versionClasses['latest'] = TRUE; } } } return array_keys($versionClasses); }