Ejemplo n.º 1
0
/**
 * 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);
}
Ejemplo n.º 2
0
 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;
 }
Ejemplo n.º 3
0
 public function prepareDocumentation()
 {
     global $wgOut, $wgParser, $wgScriptPath, $wgTitle, $wgUser;
     /**
      * We need a lot of stuff from our PonyDocs extension!
      */
     $ponydocs = PonyDocsWiki::getInstance($this->data['selectedProduct']);
     $this->data['manuals'] = $ponydocs->getManualsForProduct($this->data['selectedProduct']);
     /**
      * Adjust content actions as needed, such as add 'view all' link.
      */
     $this->contentActions();
     $this->navURLS();
     /**
      * Possible topic syntax we must handle:
      * 
      * Documentation:<topic> *Which may include a version tag at the end, we don't care about this.
      * Documentation:<productShortName>:<manualShortName>:<topic>:<version>
      * Documentation:<productShortName>:<manualShortName>
      */
     /**
      * Based on the name; i.e. 'Documentation:Product:Manual:Topic' we need to parse it out and store the manual name and
      * the topic name as parameters. We store manual in 'manualname' and topic in 'topicname'. Special handling
      * needs to be done for versions and TOC?
      *
      * 	0=NS (Documentation)
      *  1=Product (Short name)
      *  2=Manual (Short name)
      *  3=Topic
      *  4=Version
      */
     $pManual = null;
     $pieces = explode(':', $wgTitle->__toString());
     $helpClass = '';
     /**
      * This isn't a specific topic+version -- handle appropriately.
      */
     if (sizeof($pieces) < 4) {
         if (!strcmp(PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $this->data['selectedProduct'] . PONYDOCS_PRODUCTVERSION_SUFFIX, $wgTitle->__toString())) {
             $this->data['titletext'] = 'Versions Management - ' . $this->data['selectedProduct'];
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>* Use {{#version:name|status}} to define a new version,' . ' where status is released, unreleased, or preview.' . ' Valid chars in version name are A-Z, 0-9, period, comma, and dash.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>* Use {{#versiongroup:name|message}} to set a banner' . ' message that will appear on every topic in every version following the versiongroup.</i></span>');
         } elseif (!strcmp(PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $this->data['selectedProduct'] . PONYDOCS_PRODUCTMANUAL_SUFFIX, $wgTitle->__toString())) {
             $this->data['titletext'] = 'Manuals Management - ' . $this->data['selectedProduct'];
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Use {{#manual:manualShortName|displayName|categories}} to define a new manual.');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Prepend manual short name with ' . PONYDOCS_PRODUCT_STATIC_PREFIX . ' to define a static manual.' . '</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* If you omit display name, the short name will be used in links.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* Categories is a comma-separated list of categories</i></span>');
         } elseif (!strcmp(PONYDOCS_DOCUMENTATION_PRODUCTS_TITLE, $wgTitle->__toString())) {
             $this->data['titletext'] = 'Products Management';
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Use {{#product:productShortName|displayName|description|parent|categories}} to define a new product.' . '</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Prepend product short name with ' . PONYDOCS_PRODUCT_STATIC_PREFIX . ' to define a static product.' . '</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* displayName, description, parent, and categories can be left empty.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* If you leave displayName empty, productShortName will be used in links.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* Categories is a comma-separated list of categories.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* Each product here <b>MUST</b> also be listed in $ponyDocsProductsList,' . ' usually configured in LocalSettings.php.</i></span>');
         } elseif (preg_match('/(.*)TOC(.*)/', $pieces[2], $matches)) {
             $this->data['titletext'] = $matches[1] . ' Table of Contents Page';
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Optionally start this page with {{#manualDescription:Manual Description.}}' . ' followed by two line-breaks to set a manual description for the Manual this TOC belongs to.' . '</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Topics are grouped into sections by section headers.' . ' Any line without markup is considered a section header.' . ' A section header is required before the the first topic tag.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Topic tags must be part of an unordered list.' . ' Use {{#topic:Display Name}} after a * (list item markup) to create topics.</i></span>');
         } elseif (sizeof($pieces) >= 2 && PonyDocsProductManual::IsManual($pieces[1], $pieces[2])) {
             $pManual = PonyDocsProductManual::GetManualByShortName($pieces[1], $pieces[2]);
             if ($pManual) {
                 $this->data['manualname'] = $pManual->getLongName();
             } else {
                 $this->data['manualname'] = $pieces[2];
             }
             $this->data['topicname'] = $pieces[3];
             $this->data['titletext'] = $pieces[2];
         } else {
             $this->data['topicname'] = $pieces[2];
         }
     } else {
         $pManual = PonyDocsProductManual::GetManualByShortName($pieces[1], $pieces[2]);
         if ($pManual) {
             $this->data['manualname'] = $pManual->getLongName();
         } else {
             $this->data['manualname'] = $pieces[2];
         }
         $this->data['topicname'] = $pieces[3];
         $h1 = PonyDocsTopic::FindH1ForTitle($wgTitle->__toString());
         if ($h1 !== FALSE) {
             $this->data['titletext'] = $h1;
         }
     }
     /**
      * Get current topic, passing it our global Article object.
      * From this, generate our TOC based on the current topic selected.
      * This generates our left sidebar TOC plus our prev/next/start navigation links.
      * This should ONLY be done if we actually are WITHIN a manual, so special pages like TOC, etc. should not do this!
      */
     if ($pManual) {
         $p = PonyDocsProduct::GetProductByShortName($this->data['selectedProduct']);
         $v = PonyDocsProductVersion::GetVersionByName($this->data['selectedProduct'], $this->data['selectedVersion']);
         $toc = new PonyDocsTOC($pManual, $v, $p);
         list($this->data['manualtoc'], $this->data['tocprev'], $this->data['tocnext'], $this->data['tocstart']) = $toc->loadContent();
         $this->data['toctitle'] = $toc->getTOCPageTitle();
     }
     /**
      * Create a PonyDocsTopic from our article. From this we populate:
      *
      * topicversions:  List of version names topic is tagged with.
      * inlinetoc:  Inline TOC shown above article body.
      * catcode:  Special category code.
      * cattext:  Category description.
      * basetopicname:  Base topic name (w/o :<version> at end).
      * basetopiclink:  Link to special TopicList page to view all same topics.
      */
     $context = $this->skin->getContext();
     $article = Article::newFromTitle($context->getTitle(), $context);
     $topic = new PonyDocsTopic($article);
     if (preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(.*):(.*):(.*):(.*)/', $wgTitle->__toString()) || preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':.*:.*TOC.*/', $wgTitle->__toString())) {
         $this->data['topicversions'] = PonyDocsWiki::getVersionsForTopic($topic);
         $this->data['inlinetoc'] = $topic->getSubContents();
         $this->data['versionclasses'] = $topic->getVersionClasses();
         $this->data['versionGroupMessage'] = $this->data['pVersion']->getVersionGroupMessage();
         /**
          * Sort of a hack -- we only use this right now when loading a TOC page which is new/does not exist.
          * When this happens a hook (AlternateEdit) adds an inline script to define this JS function,
          * which populates the edit box with the proper Category tag based on the currently selected version.
          */
         $this->data['body_onload'] = 'ponyDocsOnLoad();';
         switch ($this->data['catcode']) {
             case 0:
                 $this->data['cattext'] = 'Applies to latest version which is currently unreleased.';
                 break;
             case 1:
                 $this->data['cattext'] = 'Applies to latest version.';
                 break;
             case 2:
                 $this->data['cattext'] = 'Applies to released version(s) but not the latest.';
                 break;
             case 3:
                 $this->data['cattext'] = 'Applies to latest preview version.';
                 break;
             case 4:
                 $this->data['cattext'] = 'Applies to one or more preview version(s) only.';
                 break;
             case 5:
                 $this->data['cattext'] = 'Applies to one or more unreleased version(s) only.';
                 break;
             case -2:
                 /** Means its not a a title name which should be checked. */
                 break;
             default:
                 $this->data['cattext'] = 'Does not apply to any version of PonyDocs.';
                 break;
         }
     }
     $this->data['basetopicname'] = $topic->getBaseTopicName();
     if (strlen($this->data['basetopicname'])) {
         $this->data['basetopiclink'] = '<a href="' . $wgScriptPath . '/index.php?title=Special:TopicList&topic=' . $this->data['basetopicname'] . '">View All</a>';
     }
     $temp = PonyDocsTopic::FindH1ForTitle(PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $topic->getTitle()->getText());
     if ($temp !== false) {
         // We got an H1!
         $this->data['pagetitle'] = $temp;
     }
 }