protected function populatePage(DatabaseBase $dbw, $ns) { $toSave = array(); $lastId = 0; $nsCondition = $ns === 'all' ? array() : array('page_namespace' => $ns); do { $rows = $dbw->select('page', array('page_namespace', 'page_title', 'page_id'), array('page_content_model' => null, 'page_id > ' . $dbw->addQuotes($lastId)) + $nsCondition, __METHOD__, array('LIMIT' => $this->mBatchSize, 'ORDER BY' => 'page_id ASC')); $this->output("Fetched {$rows->numRows()} rows.\n"); foreach ($rows as $row) { $title = Title::newFromRow($row); $model = ContentHandler::getDefaultModelFor($title); $toSave[$model][] = $row->page_id; if (count($toSave[$model]) >= $this->mBatchSize) { $this->updatePageRows($dbw, $toSave[$model], $model); unset($toSave[$model]); } $lastId = $row->page_id; } } while ($rows->numRows() >= $this->mBatchSize); foreach ($toSave as $model => $pages) { $this->updatePageRows($dbw, $pages, $model); } }
/** * Get the page's content model id, see the CONTENT_MODEL_XXX constants. * * @param int $flags A bit field; may be Title::GAID_FOR_UPDATE to select for update * @return string Content model id */ public function getContentModel($flags = 0) { if (!$this->mContentModel && $this->getArticleID($flags)) { $linkCache = LinkCache::singleton(); $linkCache->addLinkObj($this); # in case we already had an article ID $this->mContentModel = $linkCache->getGoodLinkFieldObj($this, 'model'); } if (!$this->mContentModel) { $this->mContentModel = ContentHandler::getDefaultModelFor($this); } return $this->mContentModel; }
/** * Dumps a "<revision>" section on the output stream, with * data filled in from the given database row. * * @param object $row * @return string * @access private */ function writeRevision($row) { wfProfileIn(__METHOD__); $out = " <revision>\n"; $out .= " " . Xml::element('id', null, strval($row->rev_id)) . "\n"; if (isset($row->rev_parent_id) && $row->rev_parent_id) { $out .= " " . Xml::element('parentid', null, strval($row->rev_parent_id)) . "\n"; } $out .= $this->writeTimestamp($row->rev_timestamp); if (isset($row->rev_deleted) && $row->rev_deleted & Revision::DELETED_USER) { $out .= " " . Xml::element('contributor', array('deleted' => 'deleted')) . "\n"; } else { $out .= $this->writeContributor($row->rev_user, $row->rev_user_text); } if (isset($row->rev_minor_edit) && $row->rev_minor_edit) { $out .= " <minor/>\n"; } if (isset($row->rev_deleted) && $row->rev_deleted & Revision::DELETED_COMMENT) { $out .= " " . Xml::element('comment', array('deleted' => 'deleted')) . "\n"; } elseif ($row->rev_comment != '') { $out .= " " . Xml::elementClean('comment', array(), strval($row->rev_comment)) . "\n"; } if (isset($row->rev_content_model) && !is_null($row->rev_content_model)) { $content_model = strval($row->rev_content_model); } else { // probably using $wgContentHandlerUseDB = false; $title = Title::makeTitle($row->page_namespace, $row->page_title); $content_model = ContentHandler::getDefaultModelFor($title); } $content_handler = ContentHandler::getForModelID($content_model); if (isset($row->rev_content_format) && !is_null($row->rev_content_format)) { $content_format = strval($row->rev_content_format); } else { // probably using $wgContentHandlerUseDB = false; $content_format = $content_handler->getDefaultFormat(); } $text = ''; if (isset($row->rev_deleted) && $row->rev_deleted & Revision::DELETED_TEXT) { $out .= " " . Xml::element('text', array('deleted' => 'deleted')) . "\n"; } elseif (isset($row->old_text)) { // Raw text from the database may have invalid chars $text = strval(Revision::getRevisionText($row)); $text = $content_handler->exportTransform($text, $content_format); $out .= " " . Xml::elementClean('text', array('xml:space' => 'preserve', 'bytes' => intval($row->rev_len)), strval($text)) . "\n"; } else { // Stub output $out .= " " . Xml::element('text', array('id' => $row->rev_text_id, 'bytes' => intval($row->rev_len)), "") . "\n"; } if (isset($row->rev_sha1) && $row->rev_sha1 && !($row->rev_deleted & Revision::DELETED_TEXT)) { $out .= " " . Xml::element('sha1', null, strval($row->rev_sha1)) . "\n"; } else { $out .= " <sha1/>\n"; } $out .= " " . Xml::element('model', null, strval($content_model)) . "\n"; $out .= " " . Xml::element('format', null, strval($content_format)) . "\n"; wfRunHooks('XmlDumpWriterWriteRevision', array(&$this, &$out, $row, $text)); $out .= " </revision>\n"; wfProfileOut(__METHOD__); return $out; }
/** * @dataProvider dataGetDefaultModelFor */ public function testGetDefaultModelFor($title, $expectedModelId) { $title = Title::newFromText($title); $this->assertEquals($expectedModelId, ContentHandler::getDefaultModelFor($title)); }
/** * Get the page's content model id, see the CONTENT_MODEL_XXX constants. * * @throws MWException * @param int $flags A bit field; may be Title::GAID_FOR_UPDATE to select for update * @return string Content model id */ public function getContentModel($flags = 0) { # Calling getArticleID() loads the field from cache as needed if (!$this->mContentModel && $this->getArticleID($flags)) { $linkCache = LinkCache::singleton(); $this->mContentModel = $linkCache->getGoodLinkFieldObj($this, 'model'); } if (!$this->mContentModel) { $this->mContentModel = ContentHandler::getDefaultModelFor($this); } if (!$this->mContentModel) { throw new MWException('Failed to determine content model!'); } return $this->mContentModel; }
protected function checkContentModel() { global $wgContentHandlerUseDB; $title = $this->getTitle(); //note: may return null for revisions that have not yet been inserted. $model = $this->getContentModel(); $format = $this->getContentFormat(); $handler = $this->getContentHandler(); if (!$handler->isSupportedFormat($format)) { $t = $title->getPrefixedDBkey(); throw new MWException("Can't use format {$format} with content model {$model} on {$t}"); } if (!$wgContentHandlerUseDB && $title) { // if $wgContentHandlerUseDB is not set, all revisions must use the default content model and format. $defaultModel = ContentHandler::getDefaultModelFor($title); $defaultHandler = ContentHandler::getForModelID($defaultModel); $defaultFormat = $defaultHandler->getDefaultFormat(); if ($this->getContentModel() != $defaultModel) { $t = $title->getPrefixedDBkey(); throw new MWException("Can't save non-default content model with \$wgContentHandlerUseDB disabled: " . "model is {$model} , default for {$t} is {$defaultModel}"); } if ($this->getContentFormat() != $defaultFormat) { $t = $title->getPrefixedDBkey(); throw new MWException("Can't use non-default content format with \$wgContentHandlerUseDB disabled: " . "format is {$format}, default for {$t} is {$defaultFormat}"); } } $content = $this->getContent(Revision::RAW); if (!$content || !$content->isValid()) { $t = $title->getPrefixedDBkey(); throw new MWException("Content of {$t} is not valid! Content model is {$model}"); } }
/** * @dataProvider provideIsCountable * @covers WikiPage::isCountable */ public function testIsCountable($title, $model, $text, $mode, $expected) { global $wgContentHandlerUseDB; $this->setMwGlobals('wgArticleCountMethod', $mode); $title = Title::newFromText($title); if (!$wgContentHandlerUseDB && $model && ContentHandler::getDefaultModelFor($title) != $model) { $this->markTestSkipped("Can not use non-default content model {$model} for " . $title->getPrefixedDBkey() . " with \$wgContentHandlerUseDB disabled."); } $page = $this->createPage($title, $text, $model); $editInfo = $page->prepareContentForEdit($page->getContent()); $v = $page->isCountable(); $w = $page->isCountable($editInfo); $this->assertEquals($expected, $v, "isCountable( null ) returned unexpected value " . var_export($v, true) . " instead of " . var_export($expected, true) . " in mode `{$mode}` for text \"{$text}\""); $this->assertEquals($expected, $w, "isCountable( \$editInfo ) returned unexpected value " . var_export($v, true) . " instead of " . var_export($expected, true) . " in mode `{$mode}` for text \"{$text}\""); }
/** * Move page to a title which is either a redirect to the * source page or nonexistent * * @fixme This was basically directly moved from Title, it should be split into smaller functions * @param User $user the User doing the move * @param Title $nt The page to move to, which should be a redirect or nonexistent * @param string $reason The reason for the move * @param bool $createRedirect Whether to leave a redirect at the old title. Does not check * if the user has the suppressredirect right * @throws MWException */ private function moveToInternal(User $user, &$nt, $reason = '', $createRedirect = true) { global $wgContLang; if ($nt->exists()) { $moveOverRedirect = true; $logType = 'move_redir'; } else { $moveOverRedirect = false; $logType = 'move'; } if ($createRedirect) { if ($this->oldTitle->getNamespace() == NS_CATEGORY && !wfMessage('category-move-redirect-override')->inContentLanguage()->isDisabled()) { $redirectContent = new WikitextContent(wfMessage('category-move-redirect-override')->params($nt->getPrefixedText())->inContentLanguage()->plain()); } else { $contentHandler = ContentHandler::getForTitle($this->oldTitle); $redirectContent = $contentHandler->makeRedirectContent($nt, wfMessage('move-redirect-text')->inContentLanguage()->plain()); } // NOTE: If this page's content model does not support redirects, $redirectContent will be null. } else { $redirectContent = null; } // Figure out whether the content model is no longer the default $oldDefault = ContentHandler::getDefaultModelFor($this->oldTitle); $contentModel = $this->oldTitle->getContentModel(); $newDefault = ContentHandler::getDefaultModelFor($nt); $defaultContentModelChanging = $oldDefault !== $newDefault && $oldDefault === $contentModel; // bug 57084: log_page should be the ID of the *moved* page $oldid = $this->oldTitle->getArticleID(); $logTitle = clone $this->oldTitle; $logEntry = new ManualLogEntry('move', $logType); $logEntry->setPerformer($user); $logEntry->setTarget($logTitle); $logEntry->setComment($reason); $logEntry->setParameters(array('4::target' => $nt->getPrefixedText(), '5::noredir' => $redirectContent ? '0' : '1')); $formatter = LogFormatter::newFromEntry($logEntry); $formatter->setContext(RequestContext::newExtraneousContext($this->oldTitle)); $comment = $formatter->getPlainActionText(); if ($reason) { $comment .= wfMessage('colon-separator')->inContentLanguage()->text() . $reason; } # Truncate for whole multibyte characters. $comment = $wgContLang->truncate($comment, 255); $dbw = wfGetDB(DB_MASTER); $oldpage = WikiPage::factory($this->oldTitle); $oldcountable = $oldpage->isCountable(); $newpage = WikiPage::factory($nt); if ($moveOverRedirect) { $newid = $nt->getArticleID(); $newcontent = $newpage->getContent(); # Delete the old redirect. We don't save it to history since # by definition if we've got here it's rather uninteresting. # We have to remove it so that the next step doesn't trigger # a conflict on the unique namespace+title index... $dbw->delete('page', array('page_id' => $newid), __METHOD__); $newpage->doDeleteUpdates($newid, $newcontent); } # Save a null revision in the page's history notifying of the move $nullRevision = Revision::newNullRevision($dbw, $oldid, $comment, true, $user); if (!is_object($nullRevision)) { throw new MWException('No valid null revision produced in ' . __METHOD__); } $nullRevision->insertOn($dbw); # Change the name of the target page: $dbw->update('page', array('page_namespace' => $nt->getNamespace(), 'page_title' => $nt->getDBkey()), array('page_id' => $oldid), __METHOD__); // clean up the old title before reset article id - bug 45348 if (!$redirectContent) { WikiPage::onArticleDelete($this->oldTitle); } $this->oldTitle->resetArticleID(0); // 0 == non existing $nt->resetArticleID($oldid); $newpage->loadPageData(WikiPage::READ_LOCKING); // bug 46397 $newpage->updateRevisionOn($dbw, $nullRevision); Hooks::run('NewRevisionFromEditComplete', array($newpage, $nullRevision, $nullRevision->getParentId(), $user)); $newpage->doEditUpdates($nullRevision, $user, array('changed' => false, 'moved' => true, 'oldcountable' => $oldcountable)); // If the default content model changes, we need to populate rev_content_model if ($defaultContentModelChanging) { $dbw->update('revision', array('rev_content_model' => $contentModel), array('rev_page' => $nt->getArticleID(), 'rev_content_model IS NULL'), __METHOD__); } if (!$moveOverRedirect) { WikiPage::onArticleCreate($nt); } # Recreate the redirect, this time in the other direction. if ($redirectContent) { $redirectArticle = WikiPage::factory($this->oldTitle); $redirectArticle->loadFromRow(false, WikiPage::READ_LOCKING); // bug 46397 $newid = $redirectArticle->insertOn($dbw); if ($newid) { // sanity $this->oldTitle->resetArticleID($newid); $redirectRevision = new Revision(array('title' => $this->oldTitle, 'page' => $newid, 'user_text' => $user->getName(), 'user' => $user->getId(), 'comment' => $comment, 'content' => $redirectContent)); $redirectRevision->insertOn($dbw); $redirectArticle->updateRevisionOn($dbw, $redirectRevision, 0); Hooks::run('NewRevisionFromEditComplete', array($redirectArticle, $redirectRevision, false, $user)); $redirectArticle->doEditUpdates($redirectRevision, $user, array('created' => true)); } } # Log the move $logid = $logEntry->insert(); $logEntry->publish($logid); }
/** * Get the page's content model id, see the CONTENT_MODEL_XXX constants. * * @throws MWException * @return String: Content model id */ public function getContentModel() { if (!$this->mContentModel) { $linkCache = LinkCache::singleton(); $this->mContentModel = $linkCache->getGoodLinkFieldObj($this, 'model'); } if (!$this->mContentModel) { $this->mContentModel = ContentHandler::getDefaultModelFor($this); } if (!$this->mContentModel) { throw new MWException('Failed to determine content model!'); } return $this->mContentModel; }