Esempio n. 1
0
 /**
  * Parse the content of the TOC management page. 
  * 
  * It should be loaded and stored and this sort of breaks the design
  * in the way that it returns the template ready array of data which PonyDocsWiki is really supposed to be returning,
  * but I do not see the point or use of an intermediate format other than to bloat the code. 
  * 
  * It returns an array of arrays, which can be stored as a single array or separated using the list() = loadContnet() syntax.
  *
  * toc: This is the actual TOC as a list of arrays,
  *	    each array having a set of keys available to specify the TOC level, text, href, etc.
  * prev: Assoc array containing the 'previous' link data (text, href), or empty if there isn't one.
  * next: Assoc array containing the 'next' link data or empty if there isn't one.
  * start: Assoc array containing the data for the FIRST topic in the TOC.
  *
  * These can be captured in a variable when calling and individually accessed or captured using the list() construct
  * i.e.: list( $toc, $prev, $next, $start ) = $toc->loadContent().
  *
  * @FIXME: Store results internally and then have a $reload flag as param.
  * $content = $toc-
  * 
  * @return array
  */
 public function loadContent()
 {
     global $wgArticlePath;
     global $wgTitle;
     global $wgScriptPath;
     global $wgPonyDocs;
     global $title;
     /**
      * From this we have the page ID of the TOC page to use -- fetch it then  parse it so we can produce an output TOC array.
      * 
      * This array will contain one array per item with the following keys:
      * - 'level': 0= Arbitary Section Name, 1= Actual topic link.
      * - 'link': Link (wiki path) to item; may be unset for section headers (or set to first section H1)?
      * - 'text': Text to show in sidebar TOC.
      * - 'current': 1 if this is the currently selected topic, 0 otherwise.
      * 
      * We also have to store the index of the current section in our loop. 
      * 
      * The reason for this is so that we can remove any sections which have no defined/valid topics listed. 
      * 
      * This will also assist in our prev/next links which are stored in special indices.
      */
     // Our title is our url.
     // We should check to see if latest is our version.
     // If so, we want to FORCE the URL to include /latest/ as the version instead of the version that the user is currently in
     $tempParts = explode("/", $title);
     $latest = FALSE;
     if (isset($tempParts[1]) && !strcmp($tempParts[1], "latest")) {
         $latest = TRUE;
     }
     $selectedProduct = $this->pProduct->getShortName();
     $selectedVersion = $this->pInitialVersion->getVersionName();
     $selectedManual = $this->pManual->getShortName();
     // Okay, let's determine if the VERSION that the user is in is latest, if so, we should set latest to true.
     if (PonyDocsProductVersion::GetLatestReleasedVersion($selectedProduct) != NULL) {
         if ($selectedVersion == PonyDocsProductVersion::GetLatestReleasedVersion($selectedProduct)->getVersionName()) {
             $latest = TRUE;
         }
     }
     $cache = PonyDocsCache::getInstance();
     $key = "TOCCACHE-" . $selectedProduct . "-" . $selectedManual . "-" . $selectedVersion;
     $toc = $cache->get($key);
     // Cache did not exist, let's load our content is build up our cache entry.
     if ($toc === NULL && is_object($this->pTOCArticle) && is_a($this->pTOCArticle, 'Article')) {
         // The current index of the element in $toc we will work on
         $idx = 0;
         $section = -1;
         $content = $this->pTOCArticle->getContent();
         $lines = explode("\n", $content);
         foreach ($lines as $line) {
             /**
              * Indicates an arbitrary section header if it does not begin with a bullet point.
              * This is level 0 in our TOC and is not a link of any type (?).
              */
             if (!isset($line[0]) || $line[0] != '*') {
                 /**
                  * See if we are CLOSING a section (i.e. $section != -1). If so, check 'subs' and ensure its >0, 
                  * otherwise we need to remove the section from the list.
                  */
                 if ($section != -1 && !$toc[$section]['subs']) {
                     unset($toc[$section]);
                 }
                 if (isset($line[0]) && ctype_alnum($line[0])) {
                     $toc[$idx] = array('level' => 0, 'subs' => 0, 'link' => '', 'text' => $line, 'current' => FALSE);
                     $section = $idx;
                 }
                 /**
                  * This is a bullet point and thus an actual topic which can be linked to in MediaWiki. 
                  * {{#topic:H1 Of Topic Page}}
                  */
             } else {
                 if (-1 == $section) {
                     continue;
                 }
                 $topicRegex = '/' . PonyDocsTopic::getTopicRegex() . '/i';
                 if (!preg_match($topicRegex, $line, $matches)) {
                     continue;
                 }
                 $baseTopic = $matches[1];
                 $title_suffix = preg_replace('/([^' . str_replace(' ', '', Title::legalChars()) . '])/', '', $baseTopic);
                 $title = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$selectedProduct}:{$selectedManual}:{$title_suffix}";
                 $newTitle = PonyDocsTopic::GetTopicNameFromBaseAndVersion($title, $selectedProduct);
                 /**
                  * Hide topics which have no content (i.e. have not been created yet) from the user viewing. 
                  * 
                  * Authors must go to the TOC page in order to view and edit these.
                  * 
                  * The only way to do this (the cleanest/quickest) is to create a Title object then see if its article ID is 0
                  * 
                  * @tbd: Fix so that the section name is hidden if no topics are visible?
                  */
                 $t = Title::newFromText($newTitle);
                 if (!$t || !$t->getArticleID()) {
                     continue;
                 }
                 /**
                  * Obtain H1 content from the article -- WE NEED TO CACHE THIS!
                  */
                 $h1 = PonyDocsTopic::FindH1ForTitle($newTitle);
                 if ($h1 === FALSE) {
                     $h1 = $newTitle;
                 }
                 $href = str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . "/{$selectedProduct}/{$selectedVersion}/{$selectedManual}/{$title_suffix}", $wgArticlePath);
                 $toc[$idx] = array('level' => 1, 'page_id' => $t->getArticleID(), 'link' => $href, 'toctitle' => $baseTopic, 'text' => $h1, 'section' => $toc[$section]['text'], 'title' => $newTitle, 'class' => 'toclevel-1');
                 $toc[$section]['subs']++;
             }
             $idx++;
         }
         if (!$toc[$section]['subs']) {
             unset($toc[$section]);
         }
         // Okay, let's store in our cache.
         $cache->put($key, $toc, TOC_CACHE_TTL, TOC_CACHE_TTL / 4);
     }
     if ($toc) {
         $currentIndex = -1;
         $start = array();
         // Go through and determine start, prev, next and current elements.
         foreach ($toc as $idx => &$entry) {
             // Not using $entry. Only interested in $idx.
             // This allows us to process tocs with removed key indexes.
             if ($toc[$idx]['level'] == 1) {
                 if (empty($start)) {
                     $start = $toc[$idx];
                 }
                 // Determine current
                 $toc[$idx]['current'] = strcmp($wgTitle->getPrefixedText(), $toc[$idx]['title']) ? FALSE : TRUE;
                 if ($toc[$idx]['current']) {
                     $currentIndex = $idx;
                 }
                 // Now rewrite link with latest, if we are in latest
                 if ($latest) {
                     $safeVersion = preg_quote($selectedVersion, '#');
                     // Lets be specific and replace the version and not some other part of the URI that might match...
                     $toc[$idx]['link'] = preg_replace('#^/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/([' . PONYDOCS_PRODUCT_LEGALCHARS . ']+)/' . "{$safeVersion}#", '/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/$1/latest', $toc[$idx]['link'], 1);
                 }
             }
         }
         /**
          * Figure out previous and next links.
          * 
          * Previous should point to previous topic regardless of section, so our best bet is to skip any 'level=0'. 
          * 
          * Next works the same way.
          */
         $prev = $next = $idx = -1;
         if ($currentIndex >= 0) {
             $idx = $currentIndex;
             while ($idx >= 0) {
                 --$idx;
                 if (isset($toc[$idx]) && $toc[$idx]['level'] == 1) {
                     $prev = $idx;
                     break;
                 }
             }
             $idx = $currentIndex;
             // Array is sparse, so sizeof() truncates the end. Use max key instead.
             while ($idx <= max(array_keys($toc))) {
                 ++$idx;
                 if (isset($toc[$idx]) && $toc[$idx]['level'] == 1) {
                     $next = $idx;
                     break;
                 }
             }
             if ($prev != -1) {
                 $prev = array('link' => $toc[$prev]['link'], 'text' => $toc[$prev]['text']);
             }
             if ($next != -1) {
                 $next = array('link' => $toc[$next]['link'], 'text' => $toc[$next]['text']);
             }
         }
         /**
          * You should typically capture this by doing:
          * list( $toc, $prev, $next, $start ) = $ponydocstoc->loadContent();
          *
          * @FIXME: Previous and next links change based on the page you are on, so we cannot CACHE those!
          *
          * $obj = new stdClass();
          * $obj->toc = $toc;
          * $obj->prev = $prev;
          * $obj->next = $next;
          * $obj->start = $start;
          * $cache->addKey($tocKey, $obj);
          */
         // Last but not least, get the manual description if there is one.
         if (is_object($this->pTOCArticle) && preg_match('/{{#manualDescription:([^}]*)}}/', $this->pTOCArticle->getContent(), $matches)) {
             $this->mManualDescription = $matches[1];
         }
         // $this->pTOCArticle is empty, we're probably creating a new TOC
     } else {
         $toc = array();
         $prev = array();
         $next = array();
         $start = array();
     }
     return array($toc, $prev, $next, $start);
 }
Esempio n. 2
0
 /**
  * This is an ArticleSaveComplete hook that creates topics which don't exist yet when saving a TOC.
  * 
  * @param WikiPage $article
  * @param User $user
  * @param string $text
  * @param string $summary
  * @param boolean $minor
  * @param boolean $watch
  * @param $sectionanchor
  * @param integer $flags
  * 
  * @deprecated Replace with PageContentSaveComplete hook
  */
 public static function onArticleSave_CheckTOC(&$article, &$user, $text, $summary, $minor, $watch, $sectionanchor, &$flags)
 {
     // Dangerous.  Only set the flag if you know that you should be skipping this processing.
     // Currently used for branch/inherit.
     if (PonyDocsExtension::isSpeedProcessingEnabled()) {
         return TRUE;
     }
     $title = $article->getTitle();
     $realArticle = Article::newFromWikiPage($article, RequestContext::getMain());
     $matches = array();
     if (preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':([' . PONYDOCS_PRODUCT_LEGALCHARS . ']*):([' . PONYDOCS_PRODUCTMANUAL_LEGALCHARS . ']*)TOC([' . PONYDOCS_PRODUCTVERSION_LEGALCHARS . ']*)/i', $title->__toString(), $match)) {
         $dbr = wfGetDB(DB_MASTER);
         /**
          * Get all topics
          */
         $topicRegex = '/' . PonyDocsTopic::getTopicRegex() . '/';
         preg_match_all($topicRegex, $text, $matches, PREG_SET_ORDER);
         /**
          * Create any topics which do not already exist in the saved TOC.
          */
         $pProduct = PonyDocsProduct::GetProductByShortName($match[1]);
         $pManual = PonyDocsProductManual::GetManualByShortName($pProduct->getShortName(), $match[2]);
         $pManualTopic = new PonyDocsTopic($realArticle);
         $manVersionList = $pManualTopic->getProductVersions();
         if (!sizeof($manVersionList)) {
             return TRUE;
         }
         // Clear all TOC cache entries for each version.
         if ($pManual) {
             foreach ($manVersionList as $version) {
                 PonyDocsTOC::clearTOCCache($pManual, $version, $pProduct);
                 PonyDocsProductVersion::clearNAVCache($version);
             }
         }
         $earliestVersion = PonyDocsProductVersion::findEarliest($pProduct->getShortName(), $manVersionList);
         foreach ($matches as $m) {
             $wikiTopic = preg_replace('/([^' . str_replace(' ', '', Title::legalChars()) . '])/', '', $m[1]);
             $wikiPath = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $match[1] . ':' . $match[2] . ':' . $wikiTopic;
             $versionIn = array();
             foreach ($manVersionList as $pV) {
                 $versionIn[] = $pProduct->getShortName() . ':' . $pV->getVersionName();
             }
             $res = $dbr->select(array('categorylinks'), 'cl_from', array("cl_to IN ('V:" . implode("','V:", $versionIn) . "')", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper("{$match[1]}:{$match[2]}:{$wikiTopic}")) . ":%'"), __METHOD__);
             $topicName = '';
             if (!$res->numRows()) {
                 /**
                  * No match -- so this is a "new" topic.  Set name and create.
                  */
                 $topicName = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $match[1] . ':' . $match[2] . ':' . $wikiTopic . ':' . $earliestVersion->getVersionName();
                 $topicArticle = new Article(Title::newFromText($topicName));
                 if (!$topicArticle->exists()) {
                     $content = "= " . $m[1] . "=\n\n";
                     foreach ($manVersionList as $pVersion) {
                         $content .= '[[Category:V:' . $pProduct->getShortName() . ':' . $pVersion->getVersionName() . ']]';
                     }
                     $topicArticle->doEdit($content, 'Auto-creation of topic ' . $topicName . ' via TOC ' . $title->__toString(), EDIT_NEW);
                     if (PONYDOCS_DEBUG) {
                         error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] Auto-created {$topicName} from TOC " . $title->__toString());
                     }
                 }
             }
         }
     }
     return TRUE;
 }
 /**
  * Do a bulk add operation. Take a collection of topics and add them to the TOC if it doesn't already exist.
  *
  * @param $manual PonyDocsManual The manual the TOC belongs to.
  * @param $version PonyDocsVersion The version the TOC belongs to.
  * @param $collection array A multidimensional array of topics. First keyed with section name, then titles.
  * @returns boolean
  */
 static function addCollectionToTOC($product, $manual, $version, $collection)
 {
     global $wgTitle;
     $title = self::TOCExists($product, $manual, $version);
     if ($title == FALSE) {
         throw new Exception("TOC does not exist for " . $manual->getShortName() . " with version " . $version->getVersionName());
     }
     $title = Title::newFromText($title);
     $wgTitle = $title;
     $article = new Article($title);
     if (!$article->exists()) {
         throw new Exception("TOC does not exist for " . $manual->getShortName() . " with version " . $version->getVersionName());
     }
     // Okay, let's search for the content.
     $content = $article->getContent();
     foreach ($collection as $sectionName => $topics) {
         // $evalSectionName is the cleaned up section name to look for.
         $evalSectionName = preg_quote(trim(str_replace('?', "", strtolower($sectionName))));
         foreach ($topics as $topic) {
             if ($topic == NULL) {
                 continue;
             }
             // $topic is the trimmed original version of the topic.
             $topic = trim($topic);
             // $evalTopic is the clened up topic name to look for
             $evalTopic = preg_quote(str_replace('?', '', strtolower($topic)));
             $content = explode("\n", $content);
             $found = FALSE;
             $inSection = FALSE;
             $newContent = '';
             foreach ($content as $line) {
                 $evalLine = trim(str_replace('?', '', strtolower($line)));
                 $topicRegex = PonyDocsTopic::getTopicRegex($evalTopic);
                 if (preg_match("/^" . $evalSectionName . "\$/", $evalLine)) {
                     $inSection = TRUE;
                     $newContent .= $line . "\n";
                     continue;
                 } elseif (preg_match("/\\*\\s*{$topicRegex}/", $evalLine)) {
                     if ($inSection) {
                         $found = TRUE;
                     }
                     $newContent .= $line . "\n";
                     continue;
                 } elseif (preg_match("/^\\s?\$/", $evalLine)) {
                     if ($inSection && !$found) {
                         $newContent .= "* {{#topic:" . $topic . "}}\n\n";
                         $found = TRUE;
                         continue;
                     }
                     $inSection = FALSE;
                 }
                 $newContent .= $line . "\n";
             }
             if (!$found) {
                 // Then the section didn't event exist, we should add to TOC and add the item.
                 // We need to add it before the Category evalLine.
                 $text = $sectionName . "\n" . "* {{#topic:" . $topic . "}}\n\n[[Category";
                 $newContent = preg_replace("/\\[\\[Category/", $text, $newContent);
             }
             $inSection = FALSE;
             // Reset loop data
             $content = $newContent;
         }
     }
     // Okay, do the edit
     $article->doEdit($content, "Updated TOC in bulk branch operation.", EDIT_UPDATE);
     return TRUE;
 }