From: Daniel Kinzler Date: Mon, 5 Mar 2012 15:53:25 +0000 (+0000) Subject: adapted WikiPage and Article (work in progress) X-Git-Tag: 1.31.0-rc.0~22097^2^2~301 X-Git-Url: http://git.cyclocoop.org/%22%20.%20generer_url_ecrire%28%22upgrade%22%2C%22reinstall=non%22%29%20.%20%22?a=commitdiff_plain;h=efdb25653db9abfc81591040a92a0dc2bd3aa08d;p=lhc%2Fweb%2Fwiklou.git adapted WikiPage and Article (work in progress) --- diff --git a/includes/Article.php b/includes/Article.php index 06c460d78f..895619ff5b 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -38,6 +38,7 @@ class Article extends Page { public $mParserOptions; var $mContent; // !< #FIXME: use Content object! + var $mContentObject; // !< var $mContentLoaded = false; // !< var $mOldId; // !< @@ -189,8 +190,25 @@ class Article extends Page { * only want the real revision text if any. * * @return Return the text of this revision - */ - public function getContent() { + * @deprecated in 1.20; use getContentObject() instead + */ + public function getContent() { #FIXME: deprecated! replace usage! use content object! + wfDeprecated( __METHOD__, '1.20' ); + $content = $this->getContentObject(); + return ContentHandler::getContentText( $content ); + } + + /** + * Note that getContent/loadContent do not follow redirects anymore. + * If you need to fetch redirectable content easily, try + * the shortcut in WikiPage::getRedirectTarget() + * + * This function has side effects! Do not use this function if you + * only want the real revision text if any. + * + * @return Return the content of this revision + */ + public function getContentObject() { global $wgUser; wfProfileIn( __METHOD__ ); @@ -208,12 +226,12 @@ class Article extends Page { } wfProfileOut( __METHOD__ ); - return $text; + return new WikitextContent( $text, $this->getTitle() ); } else { - $this->fetchContent(); + $this->fetchContentObject(); wfProfileOut( __METHOD__ ); - return $this->mContent; + return $this->mContentObject; } } @@ -292,61 +310,89 @@ class Article extends Page { * Does *NOT* follow redirects. * * @return mixed string containing article contents, or false if null + * @deprecated in 1.20, use getContentObject() instead */ - function fetchContent() { - if ( $this->mContentLoaded ) { + function fetchContent() { #BC cruft! #FIXME: deprecated, replace usage + wfDeprecated( __METHOD__, '1.20' ); + + if ( $this->mContentLoaded && $this->mContent ) { return $this->mContent; } wfProfileIn( __METHOD__ ); - $this->mContentLoaded = true; - - $oldid = $this->getOldID(); - - # Pre-fill content with error message so that if something - # fails we'll have something telling us what we intended. - $t = $this->getTitle()->getPrefixedText(); - $d = $oldid ? wfMsgExt( 'missingarticle-rev', array( 'escape' ), $oldid ) : ''; - $this->mContent = wfMsgNoTrans( 'missing-article', $t, $d ) ; - - if ( $oldid ) { - # $this->mRevision might already be fetched by getOldIDFromRequest() - if ( !$this->mRevision ) { - $this->mRevision = Revision::newFromId( $oldid ); - if ( !$this->mRevision ) { - wfDebug( __METHOD__ . " failed to retrieve specified revision, id $oldid\n" ); - wfProfileOut( __METHOD__ ); - return false; - } - } - } else { - if ( !$this->mPage->getLatest() ) { - wfDebug( __METHOD__ . " failed to find page data for title " . $this->getTitle()->getPrefixedText() . "\n" ); - wfProfileOut( __METHOD__ ); - return false; - } - - $this->mRevision = $this->mPage->getRevision(); - if ( !$this->mRevision ) { - wfDebug( __METHOD__ . " failed to retrieve current page, rev_id " . $this->mPage->getLatest() . "\n" ); - wfProfileOut( __METHOD__ ); - return false; - } - } - - // @todo FIXME: Horrible, horrible! This content-loading interface just plain sucks. - // We should instead work with the Revision object when we need it... - $this->mContent = $this->mRevision->getText( Revision::FOR_THIS_USER ); // Loads if user is allowed - $this->mRevIdFetched = $this->mRevision->getId(); + $content = $this->fetchContentObject(); - wfRunHooks( 'ArticleAfterFetchContent', array( &$this, &$this->mContent ) ); + $this->mContent = ContentHandler::getContentText( $content ); + wfRunHooks( 'ArticleAfterFetchContent', array( &$this, &$this->mContent ) ); #BC cruft! wfProfileOut( __METHOD__ ); return $this->mContent; } + + /** + * Get text content object + * Does *NOT* follow redirects. + * + * @return Content object containing article contents, or null + */ + function fetchContentObject() { + if ( $this->mContentLoaded ) { + return $this->mContentObject; + } + + wfProfileIn( __METHOD__ ); + + $this->mContentLoaded = true; + $this->mContent = null; + + $oldid = $this->getOldID(); + + # Pre-fill content with error message so that if something + # fails we'll have something telling us what we intended. + $t = $this->getTitle()->getPrefixedText(); + $d = $oldid ? wfMsgExt( 'missingarticle-rev', array( 'escape' ), $oldid ) : ''; + $this->mContentObject = new MessageContent( 'missing-article', array($t, $d), array() ) ; + + if ( $oldid ) { + # $this->mRevision might already be fetched by getOldIDFromRequest() + if ( !$this->mRevision ) { + $this->mRevision = Revision::newFromId( $oldid ); + if ( !$this->mRevision ) { + wfDebug( __METHOD__ . " failed to retrieve specified revision, id $oldid\n" ); + wfProfileOut( __METHOD__ ); + return false; + } + } + } else { + if ( !$this->mPage->getLatest() ) { + wfDebug( __METHOD__ . " failed to find page data for title " . $this->getTitle()->getPrefixedText() . "\n" ); + wfProfileOut( __METHOD__ ); + return false; + } + + $this->mRevision = $this->mPage->getRevision(); + if ( !$this->mRevision ) { + wfDebug( __METHOD__ . " failed to retrieve current page, rev_id " . $this->mPage->getLatest() . "\n" ); + wfProfileOut( __METHOD__ ); + return false; + } + } + + // @todo FIXME: Horrible, horrible! This content-loading interface just plain sucks. + // We should instead work with the Revision object when we need it... + $this->mContentObject = $this->mRevision->getContent( Revision::FOR_THIS_USER ); // Loads if user is allowed + $this->mRevIdFetched = $this->mRevision->getId(); + + wfRunHooks( 'ArticleAfterFetchContentObject', array( &$this, &$this->mContentObject ) ); #FIXME: register new hook + + wfProfileOut( __METHOD__ ); + + return $this->mContentObject; + } + /** * No-op * @deprecated since 1.18 diff --git a/includes/Content.php b/includes/Content.php index b8e138e7b8..1a445c669e 100644 --- a/includes/Content.php +++ b/includes/Content.php @@ -68,6 +68,8 @@ class TextContent extends Content { $html = $this->getHtml( $options ); $po = new ParserOutput( $html ); + if ( $this->mTitle ) $po->setTitleText( $this->mTitle->getText() ); + #TODO: cache settings, etc? return $po; @@ -84,8 +86,6 @@ class TextContent extends Content { public function getRawData( ) { - global $wgParser, $wgUser; - $text = $this->mText; return $text; } @@ -128,6 +128,35 @@ class WikitextContent extends TextContent { } +class MessageContent extends TextContent { + public function __construct( $msg_key, $params = null, $options = null ) { + parent::__construct(null, null, null, CONTENT_MODEL_WIKITEXT); + + $this->mMessageKey = $msg_key; + + $this->mParameters = $params; + + if ( !$options ) $options = array(); + $this->mOptions = $options; + + $this->mHtmlOptions = null; + } + + + public function getHtml( ParserOptions $options ) { + $opt = array_merge( $this->mOptions, array('parse') ); + return wfMsgExt( $this->mMessageKey, $this->mParameters, $opt ); + } + + + public function getRawData( ) { + $opt = array_diff( $this->mOptions, array('parse', 'parseinline') ); + + return wfMsgExt( $this->mMessageKey, $this->mParameters, $opt ); + } + +} + class JavaScriptContent extends TextContent { public function __construct( $text, Title $title, $revId = null ) { @@ -160,6 +189,9 @@ class CssContent extends TextContent { } } +#FIXME: special type for redirects?! +#FIXME: special type for message-based pseudo-content? with raw html? + #TODO: MultipartMultipart < WikipageContent (Main + Links + X) #TODO: LinksContent < LanguageLinksContent, CategoriesContent #EXAMPLE: CoordinatesContent diff --git a/includes/ContentHandler.php b/includes/ContentHandler.php index b7761d63af..025c740c27 100644 --- a/includes/ContentHandler.php +++ b/includes/ContentHandler.php @@ -13,6 +13,18 @@ */ abstract class ContentHandler { + public static function getContentText( Content $content ) { + if ( !$content ) return ''; + + if ( $content instanceof TextContent ) { + #XXX: or check by model name? + #XXX: or define $content->allowRawData()? + return $content->getRawData(); + } + + return null; + } + public static function getDefaultModelFor( Title $title ) { global $wgNamespaceContentModels; diff --git a/includes/Revision.php b/includes/Revision.php index 4e2a091d0c..9bc9469a92 100644 --- a/includes/Revision.php +++ b/includes/Revision.php @@ -21,7 +21,9 @@ class Revision { protected $mTitle; protected $mCurrent; protected $mContentModelName; - protected $mContentType; + protected $mContentFormat; + protected $mContent; + protected $mContentHandler; const DELETED_TEXT = 1; const DELETED_COMMENT = 2; @@ -128,7 +130,7 @@ class Revision { 'len' => $row->ar_len, 'sha1' => isset( $row->ar_sha1 ) ? $row->ar_sha1 : null, 'content_model' => isset( $row->ar_content_model ) ? $row->ar_content_model : null, - 'content_type' => isset( $row->ar_content_type ) ? $row->ar_content_type : null, + 'content_format' => isset( $row->ar_content_format ) ? $row->ar_content_format : null, ); if ( isset( $row->ar_text ) && !$row->ar_text_id ) { // Pre-1.5 ar_text row @@ -339,7 +341,9 @@ class Revision { 'rev_deleted', 'rev_len', 'rev_parent_id', - 'rev_sha1' + 'rev_sha1', + 'rev_content_format', + 'rev_content_model' ); } @@ -422,10 +426,10 @@ class Revision { $this->mContentModelName = strval( $row->rev_content_model ); } - if( !isset( $row->rev_content_type ) || is_null( $row->rev_content_type ) ) { - $this->mContentType = null; # determine on demand if needed + if( !isset( $row->rev_content_format ) || is_null( $row->rev_content_format ) ) { + $this->mContentFormat = null; # determine on demand if needed } else { - $this->mContentType = strval( $row->rev_content_type ); + $this->mContentFormat = strval( $row->rev_content_format ); } // Lazy extraction... @@ -449,6 +453,19 @@ class Revision { // Build a new revision to be saved... global $wgUser; // ugh + + # if we have a content object, use it to set the model and type + if ( !empty( $row['content'] ) ) { + if ( !empty( $row['text_id'] ) ) { #FIXME: when is that set? test with external store setup! check out insertOn() + throw new MWException( "Text already stored in external store (id {$row['text_id']}), can't serialize content object" ); + } + + $row['content_model'] = $row['content']->getModelName(); + # note: mContentFormat is initializes later accordingly + # note: content is serialized later in this method! + # also set text to null? + } + $this->mId = isset( $row['id'] ) ? intval( $row['id'] ) : null; $this->mPage = isset( $row['page'] ) ? intval( $row['page'] ) : null; $this->mTextId = isset( $row['text_id'] ) ? intval( $row['text_id'] ) : null; @@ -462,12 +479,12 @@ class Revision { $this->mSha1 = isset( $row['sha1'] ) ? strval( $row['sha1'] ) : null; $this->mContentModelName = isset( $row['content_model'] ) ? strval( $row['content_model'] ) : null; - $this->mContentType = isset( $row['content_type'] ) ? strval( $row['content_type'] ) : null; + $this->mContentFormat = isset( $row['content_format'] ) ? strval( $row['content_format'] ) : null; - if( !isset( $row->rev_content_type ) || is_null( $row->rev_content_type ) ) { - $this->mContentType = null; # determine on demand if needed + if( !isset( $row->rev_content_format ) || is_null( $row->rev_content_format ) ) { + $this->mContentFormat = null; # determine on demand if needed } else { - $this->mContentType = $row->rev_content_type; + $this->mContentFormat = $row->rev_content_format; } // Enforce spacing trimming on supplied text @@ -487,11 +504,20 @@ class Revision { } $this->getContentModelName(); # force lazy init - $this->getContentType(); # force lazy init + $this->getContentFormat(); # force lazy init + + # if we have a content object, serialize it, overriding mText + if ( !empty( $row['content'] ) ) { + $handler = $this->getContentHandler(); + $this->mText = $handler->serialize( $row['content'], $this->getContentFormat() ); + } } else { throw new MWException( 'Revision constructor passed invalid row format.' ); } $this->mUnpatrolled = null; + + #FIXME: add patch for ar_content_format, ar_content_model, rev_content_format, rev_content_model to installer + #FIXME: add support for ar_content_format, ar_content_model, rev_content_format, rev_content_model to API } /** @@ -755,19 +781,9 @@ class Revision { */ public function getText( $audience = self::FOR_PUBLIC, User $user = null ) { #FIXME: deprecated, replace usage! wfDeprecated( __METHOD__, '1.20' ); - $content = $this->getContent(); - - if ( $content == null ) { - return ""; # not allowed - } - if ( $content instanceof TextContent ) { - #FIXME: or check by model name? or define $content->allowRawData()? - return $content->getRawData(); - } - - #TODO: log this failure! - return null; + $content = $this->getContent(); + return ContentHandler::getContentText( $content ); # returns the raw content text, if applicable } /** @@ -818,14 +834,14 @@ class Revision { // Revision is immutable. Load on demand: $handler = $this->getContentHandler(); - $type = $this->getContentType(); + $format = $this->getContentFormat(); if( is_null( $this->mText ) ) { // Load text on demand: $this->mText = $this->loadText(); } - $this->mContent = $handler->unserialize( $this->mText, $type ); + $this->mContent = $handler->unserialize( $this->mText, $format ); } return $this->mContent; @@ -840,19 +856,22 @@ class Revision { return $this->mContentModelName; } - public function getContentType() { - if ( !$this->mContentType ) { + public function getContentFormat() { + if ( !$this->mContentFormat ) { $handler = $this->getContentHandler(); - $this->mContentType = $handler->getDefaultFormat(); + $this->mContentFormat = $handler->getDefaultFormat(); } - return $this->mContentType; + return $this->mContentFormat; } public function getContentHandler() { if ( !$this->mContentHandler ) { $m = $this->getModelName(); $this->mContentHandler = ContentHandler::getForModelName( $m ); + + #XXX: do we need to verify that mContentHandler supports mContentFormat? + # otherwise, a fixed content format may cause problems on insert. } return $this->mContentHandler; @@ -1098,7 +1117,7 @@ class Revision { ? Revision::base36Sha1( $this->mText ) : $this->mSha1, 'rev_content_model' => $this->getContentModelName(), - 'rev_content_type' => $this->getContentType(), + 'rev_content_format' => $this->getContentFormat(), ), __METHOD__ ); @@ -1199,7 +1218,7 @@ class Revision { $current = $dbw->selectRow( array( 'page', 'revision' ), array( 'page_latest', 'rev_text_id', 'rev_len', 'rev_sha1', - 'rev_content_model', 'rev_content_type' ), + 'rev_content_model', 'rev_content_format' ), array( 'page_id' => $pageId, 'page_latest=rev_id', @@ -1216,7 +1235,7 @@ class Revision { 'len' => $current->rev_len, 'sha1' => $current->rev_sha1, 'content_model' => $current->rev_content_model, - 'content_type' => $current->rev_content_type + 'content_format' => $current->rev_content_format ) ); } else { $revision = null; diff --git a/includes/WikiPage.php b/includes/WikiPage.php index a0709b8891..e68a697ad7 100644 --- a/includes/WikiPage.php +++ b/includes/WikiPage.php @@ -161,6 +161,7 @@ class WikiPage extends Page { 'page_touched', 'page_latest', 'page_len', + 'page_content_model', ); } @@ -383,6 +384,23 @@ class WikiPage extends Page { return null; } + /** + * Get the content of the current revision. No side-effects... + * + * @param $audience Integer: one of: + * Revision::FOR_PUBLIC to be displayed to all users + * Revision::FOR_THIS_USER to be displayed to $wgUser + * Revision::RAW get the text regardless of permissions + * @return String|null The content of the current revision + */ + public function getContent( $audience = Revision::FOR_PUBLIC ) { + $this->loadLastEdit(); + if ( $this->mLastRevision ) { + return $this->mLastRevision->getContent( $audience ); + } + return false; + } + /** * Get the text of the current revision. No side-effects... * @@ -391,8 +409,10 @@ class WikiPage extends Page { * Revision::FOR_THIS_USER to be displayed to $wgUser * Revision::RAW get the text regardless of permissions * @return String|false The text of the current revision + * @deprecated as of 1.20, getContent() should be used instead. */ - public function getText( $audience = Revision::FOR_PUBLIC ) { + public function getText( $audience = Revision::FOR_PUBLIC ) { #FIXME: deprecated, replace usage! + wfDeprecated( __METHOD__, '1.20' ); $this->loadLastEdit(); if ( $this->mLastRevision ) { return $this->mLastRevision->getText( $audience ); @@ -405,12 +425,8 @@ class WikiPage extends Page { * * @return String|false The text of the current revision */ - public function getRawText() { - $this->loadLastEdit(); - if ( $this->mLastRevision ) { - return $this->mLastRevision->getRawText(); - } - return false; + public function getRawText() { #FIXME: deprecated, replace usage! + return $this->getText( Revision::RAW ); } /** @@ -1293,7 +1309,7 @@ class WikiPage extends Page { 'page' => $this->getId(), 'comment' => $summary, 'minor_edit' => $isminor, - 'text' => $text, + 'text' => $text, #FIXME: set content instead, leavfe serialization to revision?! 'parent_id' => $oldid, 'user' => $user->getId(), 'user_text' => $user->getName(), @@ -1963,7 +1979,9 @@ class WikiPage extends Page { 'ar_len' => 'rev_len', 'ar_page_id' => 'page_id', 'ar_deleted' => $bitfield, - 'ar_sha1' => 'rev_sha1' + 'ar_sha1' => 'rev_content_model', + 'ar_content_format' => 'rev_content_format', + 'ar_content_format' => 'rev_sha1' ), array( 'page_id' => $id, 'page_id = rev_page' diff --git a/includes/specials/SpecialUndelete.php b/includes/specials/SpecialUndelete.php index 9ed20f33cd..1cf63dd582 100644 --- a/includes/specials/SpecialUndelete.php +++ b/includes/specials/SpecialUndelete.php @@ -116,7 +116,8 @@ class PageArchive { $res = $dbr->select( 'archive', array( 'ar_minor_edit', 'ar_timestamp', 'ar_user', 'ar_user_text', - 'ar_comment', 'ar_len', 'ar_deleted', 'ar_rev_id', 'ar_sha1' + 'ar_comment', 'ar_len', 'ar_deleted', 'ar_rev_id', 'ar_sha1', + 'ar_content_format', 'ar_content_model' ), array( 'ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey() ), @@ -189,6 +190,8 @@ class PageArchive { 'ar_deleted', 'ar_len', 'ar_sha1', + 'ar_content_format', + 'ar_content_model', ), array( 'ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), @@ -463,7 +466,9 @@ class PageArchive { 'ar_deleted', 'ar_page_id', 'ar_len', - 'ar_sha1' ), + 'ar_sha1', + 'ar_content_format', + 'ar_content_model' ), /* WHERE */ array( 'ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(),