*
* @since WD.1
*
- * @return int The model id
+ * @return String The model id
*/
public function getModel();
*
* @since WD.1
*
- * @return ContentHandler
+ * @return String
*/
public function getDefaultFormat();
*/
public function preloadTransform( Title $title, ParserOptions $popts );
+ /**
+ * Prepare Content for saving. Called before Content is saved by WikiPage::doEditContent().
+ * This may be used to store additional information in the database, or check the content's
+ * consistency with global state.
+ *
+ * Note that this method will be called inside the same transaction bracket that will be used
+ * to save the new revision.
+ *
+ * @param WikiPage $page The page to be saved.
+ * @param int $flags bitfield for use with EDIT_XXX constants, see WikiPage::doEditContent()
+ * @param int $baseRevId the ID of the current revision
+ * @param User $user
+ *
+ * @return Status A status object indicating whether the content was successfully prepared for saving.
+ * If the returned status indicates an error, a rollback will be performed and the
+ * transaction aborted.
+ *
+ * @see see WikiPage::doEditContent()
+ */
+ public function prepareSave( WikiPage $page, $flags, $baseRevId, User $user );
+
# TODO: handle ImagePage and CategoryPage
# TODO: make sure we cover lucene search / wikisearch.
# TODO: make sure ReplaceTemplates still works
# FUTURE: special type for redirects?!
# FUTURE: MultipartMultipart < WikipageContent (Main + Links + X)
# FUTURE: LinksContent < LanguageLinksContent, CategoriesContent
-
- // @TODO: add support for ar_content_format, ar_content_model,
- // rev_content_format, rev_content_model to API
}
protected $model_id;
/**
- * @param $model_id int
+ * @param String $model_id
*/
public function __construct( $model_id = null ) {
$this->model_id = $model_id;
*/
protected function checkModelID( $model_id ) {
if ( $model_id !== $this->model_id ) {
- $model_name = ContentHandler::getContentModelName( $model_id );
- $own_model_name = ContentHandler::getContentModelName( $this->model_id );
-
- throw new MWException( "Bad content model: " .
- "expected {$this->model_id} ($own_model_name) " .
- "but got $model_id ($model_name)." );
+ throw new MWException( "Bad content model: " .
+ "expected {$this->model_id} " .
+ "but got $model_id." );
}
}
public function preloadTransform( Title $title, ParserOptions $popts ) {
return $this;
}
+
+ /**
+ * @see Content::prepareSave()
+ */
+ public function prepareSave( WikiPage $page, $flags, $baseRevId, User $user ) {
+ if ( $this->isValid() ) {
+ return Status::newGood();
+ } else {
+ return Status::newFatal( "invalid-content-data" );
+ }
+ }
}
/**
$sectionModelId = $with->getModel();
if ( $sectionModelId != $myModelId ) {
- $myModelName = ContentHandler::getContentModelName( $myModelId );
- $sectionModelName = ContentHandler::getContentModelName( $sectionModelId );
-
- throw new MWException( "Incompatible content model for section: " .
- "document uses $myModelId ($myModelName), " .
- "section uses $sectionModelId ($sectionModelName)." );
+ throw new MWException( "Incompatible content model for section: " .
+ "document uses $myModelId but " .
+ "section uses $sectionModelId." );
}
$oldtext = $this->getNativeData();
* @since WD.1
*
* @static
- * @param $modelId int The ID of the content model for which to get a
+ * @param $modelId String The ID of the content model for which to get a
* handler. Use CONTENT_MODEL_XXX constants.
* @return ContentHandler The ContentHandler singleton for handling the
* model given by $modelId
return ContentHandler::$handlers[$modelId];
}
- /**
- * Returns the appropriate MIME type for a given content format,
- * or null if no MIME type is known for this format.
- *
- * MIME types can be registered in the global array $wgContentFormatMimeTypes.
- *
- * @static
- * @param $id int The content format id, as given by a CONTENT_FORMAT_XXX
- * constant or returned by Revision::getContentFormat().
- *
- * @return string|null The content format's MIME type.
- */
- public static function getContentFormatMimeType( $id ) {
- global $wgContentFormatMimeTypes;
-
- if ( !isset( $wgContentFormatMimeTypes[ $id ] ) ) {
- return null;
- }
-
- return $wgContentFormatMimeTypes[ $id ];
- }
-
- /**
- * Returns the content format if for a given MIME type,
- * or null if no format ID if known for this MIME type.
- *
- * Mime types can be registered in the global array $wgContentFormatMimeTypes.
- *
- * @static
- * @param $mime string the MIME type
- *
- * @return int|null The format ID, as defined by a CONTENT_FORMAT_XXX constant
- */
- public static function getContentFormatID( $mime ) {
- global $wgContentFormatMimeTypes;
-
- static $format_ids = null;
-
- if ( $format_ids === null ) {
- $format_ids = array_flip( $wgContentFormatMimeTypes );
- }
-
- if ( !isset( $format_ids[ $mime ] ) ) {
- return null;
- }
-
- return $format_ids[ $mime ];
- }
-
- /**
- * Returns the symbolic name for a given content model.
- *
- * @param $id int The content model ID, as given by a CONTENT_MODEL_XXX
- * constant or returned by Revision::getContentModel().
- *
- * @return string The content model's symbolic name.
- * @throws MWException if the model id isn't known.
- */
- public static function getContentModelName( $id ) {
- $handler = self::getForModelID( $id );
- return $handler->getModelName();
- }
-
-
/**
* Returns the localized name for a given content model.
*
* have the form content-model-$name, where $name is getContentModelName( $id ).
*
* @static
- * @param $id int The content model ID, as given by a CONTENT_MODEL_XXX
+ * @param $name String The content model ID, as given by a CONTENT_MODEL_XXX
* constant or returned by Revision::getContentModel().
- * @todo also accept a symbolic name instead of a numeric id
*
* @return string The content format's localized name.
* @throws MWException if the model id isn't known.
*/
- public static function getLocalizedName( $id ) {
- $name = self::getContentModelName( $id );
+ public static function getLocalizedName( $name ) {
$key = "content-model-$name";
if ( wfEmptyMsg( $key ) ) return $name;
else return wfMsg( $key );
}
+ public static function getAllContentFormats() {
+ global $wgContentHandlers;
+
+ $formats = array();
+
+ foreach ( $wgContentHandlers as $model => $class ) {
+ $handler = ContentHandler::getForModelID( $model );
+ $formats = array_merge( $formats, $handler->getSupportedFormats() );
+ }
+
+ $formats = array_unique( $formats );
+ return $formats;
+ }
+
// ------------------------------------------------------------------------
protected $mModelID;
- protected $mModelName;
protected $mSupportedFormats;
/**
* and a list of supported formats. Values for the parameters are typically
* provided as literals by subclass's constructors.
*
- * @param $modelId int (use CONTENT_MODEL_XXX constants).
+ * @param $modelId String (use CONTENT_MODEL_XXX constants).
* @param $formats array List for supported serialization formats
* (typically as MIME types)
*/
*
* @abstract
* @param $content Content The Content object to serialize
- * @param $format null The desired serialization format
+ * @param $format null|String The desired serialization format
* @return string Serialized form of the content
*/
public abstract function serializeContent( Content $content, $format = null );
*
* @abstract
* @param $blob string serialized form of the content
- * @param $format null the format used for serialization
+ * @param $format null|String the format used for serialization
* @return Content the Content object created by deserializing $blob
*/
public abstract function unserializeContent( $blob, $format = null );
*
* @since WD.1
*
- * @return int The model ID
+ * @return String The model ID
*/
public function getModelID() {
return $this->mModelID;
}
- /**
- * Returns the content model's symbolic name.
- *
- * The symbolic name is is this object's class name in lower case with the trailing "ContentHandler"
- * and and special characters removed.
- *
- * @since WD.1
- *
- * @return String The content model's name
- */
- public function getModelName() {
- return $this->mModelName;
- }
-
/**
* Throws an MWException if $model_id is not the ID of the content model
* supported by this ContentHandler.
*
* @since WD.1
*
- * @param $model_id int The model to check
+ * @param String $model_id The model to check
*
* @throws MWException
*/
protected function checkModelID( $model_id ) {
if ( $model_id !== $this->mModelID ) {
- $model_name = ContentHandler::getContentModelName( $model_id );
- $own_model_name = ContentHandler::getContentModelName( $this->mModelID );
-
throw new MWException( "Bad content model: " .
- "expected {$this->mModelID} ($own_model_name) " .
- "but got $model_id ($model_name)." );
+ "expected {$this->mModelID} " .
+ "but got $model_id." );
}
}
}
}
- /**
- * Returns true if the content is consistent with the database, that is if
- * saving it to the database would not violate any global constraints.
- *
- * Content needs to be valid using this method before it can be saved.
- *
- * This default implementation always returns true.
- *
- * @since WD.1
- *
- * @param $content \Content
- *
- * @return boolean
- */
- public function isConsistentWithDatabase( Content $content ) {
- return true;
- }
-
/**
* Returns overrides for action handlers.
* Classes listed here will be used instead of the default one when
return new $diffEngineClass( $context, $old, $new, $rcid, $refreshCache, $unhide );
}
+ /**
+ * Get the language in which the content of the given page is written.
+ *
+ * This default implementation returns $wgContLang->getCode().
+ *
+ * Note that a page's language must be permanent and cacheable, that is, it must not depend
+ * on user preferences, request parameters or session state.
+ *
+ * Also note that the page language may or may not depend on the actual content of the page,
+ * that is, this method may load the content in order to determine the language.
+ *
+ * @since 1.WD
+ *
+ * @param Title $title the page to determine the language for.
+ * @param Content|null $content the page's content, if you have it handy, to avoid reloading it.
+ *
+ * @return Language the page's language code
+ */
+ public function getPageLanguage( Title $title, Content $content = null ) {
+ global $wgContLang;
+ return $wgContLang;
+ }
+
/**
* Returns the name of the diff engine to use.
*
return new JavaScriptContent( '' );
}
+ /**
+ * Returns the english language, because JS is english, and should be handled as such.
+ *
+ * @return Language wfGetLangObj( 'en' )
+ *
+ * @see ContentHandler::getPageLanguage()
+ */
+ public function getPageLanguage( Title $title, Content $content = null ) {
+ return wfGetLangObj( 'en' );
+ }
+
protected function getHtml( Content $content ) {
$html = "";
$html .= "<pre class=\"mw-code mw-js\" dir=\"ltr\">\n";
return new CssContent( '' );
}
+ /**
+ * Returns the english language, because CSS is english, and should be handled as such.
+ *
+ * @return Language wfGetLangObj( 'en' )
+ *
+ * @see ContentHandler::getPageLanguage()
+ */
+ public function getPageLanguage( Title $title, Content $content = null ) {
+ return wfGetLangObj( 'en' );
+ }
protected function getHtml( Content $content ) {
$html = "";
CONTENT_MODEL_WIKITEXT => 'WikitextContentHandler', // the usual case
CONTENT_MODEL_JAVASCRIPT => 'JavaScriptContentHandler', // dumb version, no syntax highlighting
CONTENT_MODEL_CSS => 'CssContentHandler', // dumb version, no syntax highlighting
- CONTENT_MODEL_TEXT => 'TextContentHandler', // dumb plain text in <pre>
-);
-
-/**
- * Mime types for content formats.
- * Each entry in the array maps a content format to a mime type.
- *
- * Extensions that define their own content formats can register
- * the appropriate mime types in this array.
- *
- * Such extensions shall use content format IDs
- * larger than 100 and register the ids they use at
- * <http://mediawiki.org/ContentHandler/registry>
- * to avoid conflicts with other extensions.
- */
-$wgContentFormatMimeTypes = array(
- CONTENT_FORMAT_WIKITEXT => 'text/x-wiki',
- CONTENT_FORMAT_JAVASCRIPT => 'text/javascript',
- CONTENT_FORMAT_CSS => 'text/css',
- CONTENT_FORMAT_TEXT => 'text/plain',
- CONTENT_FORMAT_HTML => 'text/html',
- CONTENT_FORMAT_XML => 'application/xml',
- CONTENT_FORMAT_JSON => 'application/json',
- CONTENT_FORMAT_SERIALIZED => 'application/vnd.php.serialized',
);
/**
/**@}*/
/**@{
- * Content model ids, used by Content and ContentHandler
+ * Content model ids, used by Content and ContentHandler.
+ * These IDs will be exposed in the API and XML dumps.
*
- * Extensions that define their own content models shall use IDs
- * larger than 100 and register the ids they use at
- * <http://mediawiki.org/ContentHandler/registry>
- * to avoid conflicts with other extensions.
+ * Extensions that define their own content model IDs should take
+ * care to avoid conflicts. Using the extension name as a prefix is recommended.
*/
-define( 'CONTENT_MODEL_WIKITEXT', 1 );
-define( 'CONTENT_MODEL_JAVASCRIPT', 2 );
-define( 'CONTENT_MODEL_CSS', 3 );
-define( 'CONTENT_MODEL_TEXT', 4 );
+define( 'CONTENT_MODEL_WIKITEXT', 'wikitext' );
+define( 'CONTENT_MODEL_JAVASCRIPT', 'javascript' );
+define( 'CONTENT_MODEL_CSS', 'css' );
+define( 'CONTENT_MODEL_TEXT', 'text' );
/**@}*/
/**@{
- * Content format ids, used by Content and ContentHandler.
- * Use ContentHander::getFormatMimeType() to get the associated mime type.
- * Register mime types in $wgContentFormatMimeTypes.
+ * Content formats, used by Content and ContentHandler.
+ * These should be MIME types, and will be exposed in the API and XML dumps.
*
- * Extensions that define their own content formats shall use IDs
- * larger than 100 and register the ids they use at
- * <http://mediawiki.org/ContentHandler/registry>
- * to avoid conflicts with other extensions.
+ * Extensions are free to use the below formats, or define their own.
+ * It is recommended to stick with the conventions for MIME types.
*/
-define( 'CONTENT_FORMAT_WIKITEXT', 1 ); // wikitext
-define( 'CONTENT_FORMAT_JAVASCRIPT', 2 ); // for js pages
-define( 'CONTENT_FORMAT_CSS', 3 ); // for css pages
-define( 'CONTENT_FORMAT_TEXT', 4 ); // for future use, e.g. with some plain-html messages.
-define( 'CONTENT_FORMAT_HTML', 5 ); // for future use, e.g. with some plain-html messages.
-define( 'CONTENT_FORMAT_SERIALIZED', 11 ); // for future use with the api, and for use by extensions
-define( 'CONTENT_FORMAT_JSON', 12 ); // for future use with the api, and for use by extensions
-define( 'CONTENT_FORMAT_XML', 13 ); // for future use with the api, and for use by extensions
+define( 'CONTENT_FORMAT_WIKITEXT', 'text/x-wiki' ); // wikitext
+define( 'CONTENT_FORMAT_JAVASCRIPT', 'text/javascript' ); // for js pages
+define( 'CONTENT_FORMAT_CSS', 'text/css' ); // for css pages
+define( 'CONTENT_FORMAT_TEXT', 'text/plain' ); // for future use, e.g. with some plain-html messages.
+define( 'CONTENT_FORMAT_HTML', 'text/html' ); // for future use, e.g. with some plain-html messages.
+define( 'CONTENT_FORMAT_SERIALIZED', 'application/vnd.php.serialized' ); // for future use with the api, and for use by extensions
+define( 'CONTENT_FORMAT_JSON', 'application/json' ); // for future use with the api, and for use by extensions
+define( 'CONTENT_FORMAT_XML', 'application/xml' ); // for future use with the api, and for use by extensions
/**@}*/
-
-
}
if ( isset( $row->rev_content_model ) && !is_null( $row->rev_content_model ) ) {
- $content_model = intval( $row->rev_content_model );
+ $content_model = strval( $row->rev_content_model );
} else {
// probably using $wgContentHandlerUseDB = false;
// @todo: test!
$content_model = ContentHandler::getDefaultModelFor( $title );
}
- $name = ContentHandler::getContentModelName( $content_model );
- $out .= " " . Xml::element('model', array( 'name' => $name ), strval( $content_model ) ) . "\n";
+ $out .= " " . Xml::element('model', null, strval( $content_model ) ) . "\n";
if ( isset( $row->rev_content_format ) && !is_null( $row->rev_content_format ) ) {
- $content_format = intval( $row->rev_content_format );
+ $content_format = strval( $row->rev_content_format );
} else {
// probably using $wgContentHandlerUseDB = false;
// @todo: test!
$content_format = $content_handler->getDefaultFormat();
}
- $mime = ContentHandler::getContentFormatMimeType( $content_format );
- $out .= " " . Xml::element('format', array( 'mime' => $mime ), strval( $content_format ) ) . "\n";
+ $out .= " " . Xml::element('format', null, strval( $content_format ) ) . "\n";
wfRunHooks( 'XmlDumpWriterWriteRevision', array( &$this, &$out, $row, $text ) );
}
/**
- * @return int
+ * @return String
*/
function getModel() {
if ( is_null( $this->model ) ) {
}
/**
- * @return int
+ * @return String
*/
function getFormat() {
if ( is_null( $this->model ) ) {
if( !isset( $row->rev_content_model ) || is_null( $row->rev_content_model ) ) {
$this->mContentModel = null; # determine on demand if needed
} else {
- $this->mContentModel = intval( $row->rev_content_model );
+ $this->mContentModel = strval( $row->rev_content_model );
}
if( !isset( $row->rev_content_format ) || is_null( $row->rev_content_format ) ) {
$this->mContentFormat = null; # determine on demand if needed
} else {
- $this->mContentFormat = intval( $row->rev_content_format );
+ $this->mContentFormat = strval( $row->rev_content_format );
}
// Lazy extraction...
$this->mParentId = isset( $row['parent_id'] ) ? intval( $row['parent_id'] ) : null;
$this->mSha1 = isset( $row['sha1'] ) ? strval( $row['sha1'] ) : null;
- $this->mContentModel = isset( $row['content_model'] ) ? intval( $row['content_model'] ) : null;
- $this->mContentFormat = isset( $row['content_format'] ) ? intval( $row['content_format'] ) : null;
+ $this->mContentModel = isset( $row['content_model'] ) ? strval( $row['content_model'] ) : null;
+ $this->mContentFormat = isset( $row['content_format'] ) ? strval( $row['content_format'] ) : null;
// Enforce spacing trimming on supplied text
$this->mComment = isset( $row['comment'] ) ? trim( strval( $row['comment'] ) ) : null;
$this->mText = isset( $row['text'] ) ? rtrim( strval( $row['text'] ) ) : null;
$this->mTextRow = null;
- # if we have a content object, override mText and mContentModel
+ $this->mTitle = isset( $row['title'] ) ? $row['title'] : null;
+
+ // if we have a Content object, override mText and mContentModel
if ( !empty( $row['content'] ) ) {
$handler = $this->getContentHandler();
$this->mContent = $row['content'];
$this->mContent = $handler->unserializeContent( $this->mText );
}
- $this->mTitle = null; # Load on demand if needed
- $this->mCurrent = false; # XXX: really? we are about to create a revision. it will usually then be the current one.
+ // if we have a Title object, override mPage. Useful for testing and convenience.
+ if ( isset( $row['title'] ) ) {
+ $this->mTitle = $row['title'];
+ $this->mPage = $this->mTitle->getArticleID();
+ } else {
+ $this->mTitle = null; // Load on demand if needed
+ }
+
+ $this->mCurrent = false; // @todo: XXX: really? we are about to create a revision. it will usually then be the current one.
- # If we still have no length, see it we have the text to figure it out
+ // If we still have no length, see it we have the text to figure it out
if ( !$this->mSize ) {
if ( !is_null( $this->mContent ) ) {
$this->mSize = $this->mContent->getSize();
}
}
- # Same for sha1
+ // Same for sha1
if ( $this->mSha1 === null ) {
$this->mSha1 = is_null( $this->mText ) ? null : self::base36Sha1( $this->mText );
}
- $this->getContentModel(); # force lazy init
- $this->getContentFormat(); # force lazy init
+ // force lazy init
+ $this->getContentModel();
+ $this->getContentFormat();
} else {
throw new MWException( 'Revision constructor passed invalid row format.' );
}
}
}
- //@todo: as a last resort, perhaps load from page table, if $this->mPage is given?!
+ if ( !$this->mTitle && !is_null( $this->mPage ) && $this->mPage > 0 ) {
+ $this->mTitle = Title::newFromID( $this->mPage );
+ }
+
return $this->mTitle;
}
* used to determine the content model to use. If no title is know, CONTENT_MODEL_WIKITEXT
* is used as a last resort.
*
- * @return int the content model id associated with this revision, see the CONTENT_MODEL_XXX constants.
+ * @return String the content model id associated with this revision, see the CONTENT_MODEL_XXX constants.
**/
public function getContentModel() {
if ( !$this->mContentModel ) {
* If no content format was stored in the database, the default format for this
* revision's content model is returned.
*
- * @return int the content format id associated with this revision, see the CONTENT_FORMAT_XXX constants.
+ * @return String the content format id associated with this revision, see the CONTENT_FORMAT_XXX constants.
**/
public function getContentFormat() {
if ( !$this->mContentFormat ) {
$format = $this->getContentFormat();
if ( !$this->mContentHandler->isSupportedFormat( $format ) ) {
- $formatName = ContentHandler::getContentFormatMimeType( $format );
- $modelName = ContentHandler::getContentModelName( $model );
-
- throw new MWException( "Oops, the content format #$format ($formatName) is not supported for this content model, #$model ($modelName)" );
+ throw new MWException( "Oops, the content format $format is not supported for this content model, $model" );
}
}
wfProfileIn( __METHOD__ );
+ $this->checkContentModel();
+
$data = $this->mText;
$flags = Revision::compressRevisionText( $data );
);
if ( $wgContentHandlerUseDB ) {
- $row[ 'rev_content_model' ] = $this->getContentModel();
- $row[ 'rev_content_format' ] = $this->getContentFormat();
- }
+ //NOTE: Store null for the default model and format, to save space.
+ //XXX: Makes the DB sensitive to changed defaults. Make this behaviour optional? Only in miser mode?
- $this->checkContentModel();
+ $model = $this->getContentModel();
+ $format = $this->getContentFormat();
+
+ $defaultModel = ContentHandler::getDefaultModelFor( $this->getTitle() );
+ $defaultFormat = ContentHandler::getForModelID( $defaultModel )->getDefaultFormat();
+
+ $row[ 'rev_content_model' ] = ( $model === $defaultModel ) ? null : $model;
+ $row[ 'rev_content_format' ] = ( $format === $defaultFormat ) ? null : $format;
+ }
$dbw->insert( 'revision', $row, __METHOD__ );
protected function checkContentModel() {
global $wgContentHandlerUseDB;
- $title = $this->getTitle(); //note: returns null for revisions that have not yet been inserted.
+ $title = $this->getTitle(); //note: may return null for revisions that have not yet been inserted.
$model = $this->getContentModel();
$format = $this->getContentFormat();
if ( !$handler->isSupportedFormat( $format ) ) {
$t = $title->getPrefixedDBkey();
- $modelName = ContentHandler::getContentModelName( $model );
- $formatName = ContentHandler::getContentFormatMimeType( $format );
- throw new MWException( "Can't use format #$format ($formatName) with content model #$model ($modelName) on $t" );
+ throw new MWException( "Can't use format $format with content model $model on $t" );
}
if ( !$wgContentHandlerUseDB && $title ) {
$defaultFormat = $defaultHandler->getDefaultFormat();
if ( $this->getContentModel() != $defaultModel ) {
- $defaultModelName = ContentHandler::getContentModelName( $defaultModel );
- $modelName = ContentHandler::getContentModelName( $model );
$t = $title->getPrefixedDBkey();
- throw new MWException( "Can't save non-default content model with \$wgContentHandlerUseDB disabled: model is #$model ($modelName), default for $t is #$defaultModel ($defaultModelName)" );
+ 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 ) {
- $defaultFormatName = ContentHandler::getContentFormatMimeType( $defaultFormat );
- $formatName = ContentHandler::getContentFormatMimeType( $format );
$t = $title->getPrefixedDBkey();
- throw new MWException( "Can't use non-default content format with \$wgContentHandlerUseDB disabled: format is #$format ($formatName), default for $t is #$defaultFormat ($defaultFormatName)" );
+ throw new MWException( "Can't use non-default content format with \$wgContentHandlerUseDB disabled: format is $format, default for $t is $defaultFormat" );
}
}
if ( !$content->isValid() ) {
$t = $title->getPrefixedDBkey();
- $modelName = ContentHandler::getContentModelName( $model );
- throw new MWException( "Content of $t is not valid! Content model is #$model ($modelName)" );
+ throw new MWException( "Content of $t is not valid! Content model is $model" );
}
}
* Abort the database transaction started via beginTransaction (if any).
*/
public function abortTransaction() {
- if ( $this->mHasTransaction ) {
+ if ( $this->mHasTransaction ) { //XXX: actually... maybe always?
$this->mDb->rollback( get_class( $this ) . '::abortTransaction' );
}
}
if ( isset( $row->page_latest ) )
$this->mLatestID = (int)$row->page_latest;
if ( isset( $row->page_content_model ) )
- $this->mContentModel = intval( $row->page_content_model );
+ $this->mContentModel = strval( $row->page_content_model );
else
$this->mContentModel = false; # initialized lazily in getContentModel()
} else { // page not found
/**
* Get the page's content model id, see the CONTENT_MODEL_XXX constants.
*
- * @return Integer: Content model id
+ * @return String: Content model id
*/
public function getContentModel() {
if ( !$this->mContentModel ) {
$this->mArticleID = $row ? intval( $row->page_id ) : 0;
$this->mRedirect = $row ? (bool)$row->page_is_redirect : false;
$this->mLatestID = $row ? intval( $row->page_latest ) : false;
- $this->mContentModel = $row && isset( $row->page_content_model ) ? intval( $row->page_content_model ) : false;
+ $this->mContentModel = $row && isset( $row->page_content_model ) ? strval( $row->page_content_model ) : false;
if ( !$this->mRedirect ) {
return false;
}
if ( $this->isSpecialPage() ) {
// special pages are in the user language
return $wgLang;
- } elseif ( $this->isCssOrJsPage() || $this->isCssJsSubpage() ) {
- // css/js should always be LTR and is, in fact, English
- return wfGetLangObj( 'en' );
} elseif ( $this->getNamespace() == NS_MEDIAWIKI ) {
// Parse mediawiki messages with correct target language
list( /* $unused */, $lang ) = MessageCache::singleton()->figureMessage( $this->getText() );
return wfGetLangObj( $lang );
}
- global $wgContLang;
- // If nothing special, it should be in the wiki content language
- $pageLang = $wgContLang;
+
+ //TODO: use the LinkCache to cache this!
+ //NOTE: ContentHandler::getPageLanguage() may need to load the content to determine the page language!
+ $contentHandler = ContentHandler::getForTitle( $this );
+ $pageLang = $contentHandler->getPageLanguage( $this );
+
// Hook at the end because we don't want to override the above stuff
wfRunHooks( 'PageContentLanguage', array( $this, &$pageLang, $wgLang ) );
return wfGetLangObj( $pageLang );
* Will use the revisions actual content model if the page exists,
* and the page's default if the page doesn't exist yet.
*
- * @return int
+ * @return String
*
* @since 1.WD
*/
}
$dbw->begin( __METHOD__ );
+
+ $prepStatus = $content->prepareSave( $this, $flags, $baseRevId, $user );
+ $status->merge( $prepStatus );
+
+ if ( !$status->isOK() ) {
+ $dbw->rollback();
+
+ wfProfileOut( __METHOD__ );
+ return $status;
+ }
+
$revisionId = $revision->insertOn( $dbw );
# Update page
$dbw->begin( __METHOD__ );
+ $prepStatus = $content->prepareSave( $this, $flags, $baseRevId, $user );
+ $status->merge( $prepStatus );
+
+ if ( !$status->isOK() ) {
+ $dbw->rollback();
+
+ wfProfileOut( __METHOD__ );
+ return $status;
+ }
+
+ $status->merge( $prepStatus );
+
# Add the page record; stake our claim on this title!
# This will return false if the article already exists
$newid = $this->insertOn( $dbw );
$this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
}
+ $contentHandler = $pageObj->getContentHandler();
+
+ // @todo ask handler whether direct editing is supported at all! make allowFlatEdit() method or some such
+
+ if ( !isset( $params['contentformat'] ) || $params['contentformat'] == '' ) {
+ $params['contentformat'] = $contentHandler->getDefaultFormat();
+ }
+
+ $contentFormat = $params['contentformat'];
+
+ if ( !$contentHandler->isSupportedFormat( $contentFormat ) ) {
+ $name = $titleObj->getPrefixedDBkey();
+ $model = $contentHandler->getModelID();
+
+ $this->dieUsage( "The requested format $contentFormat is not supported for content model $model used by $name", 'badformat' );
+ }
+
$apiResult = $this->getResult();
if ( $params['redirect'] ) {
$this->dieUsageMsg( $errors[0] );
}
- $articleObj = Article::newFromTitle( $titleObj, $this->getContext() );
-
$toMD5 = $params['text'];
if ( !is_null( $params['appendtext'] ) || !is_null( $params['prependtext'] ) )
{
- // For non-existent pages, Article::getContent()
- // returns an interface message rather than ''
- // We do want getContent()'s behavior for non-existent
- // MediaWiki: pages, though
- if ( $articleObj->getID() == 0 && $titleObj->getNamespace() != NS_MEDIAWIKI ) {
- $content = null;
- $text = '';
- } else {
- $content = $articleObj->getContentObject();
- $text = ContentHandler::getContentText( $content ); #FIXME: serialize?! get format from params?...
+ $content = $pageObj->getContent();
+
+ if ( !( $content instanceof TextContent ) ) {
+ // @todo: ContentHandler should have an isFlat() method or some such
+ // @todo: XXX: or perhaps there should be Content::append(), Content::prepend() and Content::supportsConcatenation()
+ $mode = $contentHandler->getModelID();
+ $this->dieUsage( "Can't append to pages using content model $mode", 'appendnotsupported' );
+ }
+
+ if ( !$content ) {
+ # If this is a MediaWiki:x message, then load the messages
+ # and return the message value for x.
+ if ( $titleObj->getNamespace() == NS_MEDIAWIKI ) {
+ $text = $titleObj->getDefaultMessageText();
+ if ( $text === false ) {
+ $text = '';
+ }
+
+ $content = ContentHandler::makeContent( $text, $this->getTitle() );
+ }
}
if ( !is_null( $params['section'] ) ) {
+ if ( !$contentHandler->supportsSections() ) {
+ $modelName = $contentHandler->getModelID();
+ $this->dieUsage( "Sections are not supported for this content model: $modelName.", 'sectionsnotsupported' );
+ }
+
// Process the content for section edits
$section = intval( $params['section'] );
- $sectionContent = $content->getSection( $section );
- $text = ContentHandler::getContentText( $sectionContent ); #FIXME: serialize?! get format from params?...
- if ( $text === false || $text === null ) {
+ $content = $content->getSection( $section );
+
+ if ( !$content ) {
$this->dieUsage( "There is no section {$section}.", 'nosuchsection' );
}
}
+
+ if ( !$content ) {
+ $text = '';
+ } else {
+ $text = $content->serialize( $contentFormat );
+ }
+
$params['text'] = $params['prependtext'] . $text . $params['appendtext'];
$toMD5 = $params['prependtext'] . $params['appendtext'];
}
$this->dieUsageMsg( array( 'nosuchrevid', $params['undoafter'] ) );
}
- if ( $undoRev->getPage() != $articleObj->getID() ) {
+ if ( $undoRev->getPage() != $pageObj->getID() ) {
$this->dieUsageMsg( array( 'revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText() ) );
}
- if ( $undoafterRev->getPage() != $articleObj->getID() ) {
+ if ( $undoafterRev->getPage() != $pageObj->getID() ) {
$this->dieUsageMsg( array( 'revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText() ) );
}
- $newtext = $articleObj->getUndoText( $undoRev, $undoafterRev );
- if ( $newtext === false ) {
+ $newContent = $contentHandler->getUndoContent( $undoRev, $undoafterRev );
+ if ( !$newContent ) {
$this->dieUsageMsg( 'undo-failure' );
}
- $params['text'] = $newtext;
+
+ $params['contentformat'] = $contentHandler->getDefaultFormat();
+ $params['text'] = $newContent->serialize( $params['contentformat'] );
+
// If no summary was given and we only undid one rev,
// use an autosummary
if ( is_null( $params['summary'] ) && $titleObj->getNextRevisionID( $undoafterRev->getID() ) == $params['undo'] ) {
// That interface kind of sucks, but it's workable
$requestArray = array(
'wpTextbox1' => $params['text'],
+ 'format' => $contentFormat,
+ 'model' => $contentHandler->getModelID(),
'wpEditToken' => $params['token'],
'wpIgnoreBlankSummary' => ''
);
if ( !is_null( $params['basetimestamp'] ) && $params['basetimestamp'] != '' ) {
$requestArray['wpEdittime'] = wfTimestamp( TS_MW, $params['basetimestamp'] );
} else {
- $requestArray['wpEdittime'] = $articleObj->getTimestamp();
+ $requestArray['wpEdittime'] = $pageObj->getTimestamp();
}
if ( !is_null( $params['starttimestamp'] ) && $params['starttimestamp'] != '' ) {
// TODO: Make them not or check if they still do
$wgTitle = $titleObj;
- $handler = ContentHandler::getForTitle( $titleObj );
- $ep = $handler->createEditPage( $articleObj );
+ $articleObject = new Article( $titleObj );
+ $ep = new EditPage( $articleObject );
$ep->setContextTitle( $titleObj );
$ep->importFormData( $req );
}
// Do the actual save
- $oldRevId = $articleObj->getRevIdFetched();
+ $oldRevId = $articleObject->getRevIdFetched();
$result = null;
// Fake $wgRequest for some hooks inside EditPage
// @todo FIXME: This interface SUCKS
$r['result'] = 'Success';
$r['pageid'] = intval( $titleObj->getArticleID() );
$r['title'] = $titleObj->getPrefixedText();
- $newRevId = $articleObj->getLatest();
+ $r['contentmodel'] = $titleObj->getContentModel();
+ $newRevId = $articleObject->getLatest();
if ( $newRevId == $oldRevId ) {
$r['nochange'] = '';
} else {
$r['oldrevid'] = intval( $oldRevId );
$r['newrevid'] = intval( $newRevId );
$r['newtimestamp'] = wfTimestamp( TS_ISO_8601,
- $articleObj->getTimestamp() );
+ $pageObj->getTimestamp() );
}
break;
array( 'unknownerror', 'retval' ),
array( 'code' => 'nosuchsection', 'info' => 'There is no section section.' ),
array( 'code' => 'invalidsection', 'info' => 'The section parameter must be set to an integer or \'new\'' ),
+ array( 'code' => 'sectionsnotsupported', 'info' => 'Sections are not supported for this type of page.' ),
+ array( 'code' => 'editnotsupported', 'info' => 'Editing of this type of page is not supported using the text based edit API.' ),
+ array( 'code' => 'appendnotsupported', 'info' => 'This type of page can not be edited by appending or prepending text.' ),
+ array( 'code' => 'badformat', 'info' => 'The requested serialization format can not be applied to the page\'s content model' ),
array( 'customcssprotected' ),
array( 'customjsprotected' ),
)
$this->token = $params['token'];
if ( !empty( $params['contentformat'] ) ) {
- $n = ContentHandler::getContentFormatID( $params['contentformat'] );
-
- if ( is_int( $n ) ) {
- $this->contentFormat = $n;
- } else {
- $this->dieUsage( "Unknown format " . $params['contentformat'], 'badformat' );
- }
+ $this->contentFormat = $params['contentformat'];
}
// Possible indexes used
} else {
$this->setWarning( "Conversion to XML is supported for wikitext only, " .
$title->getPrefixedDBkey() .
- " uses content model #" . $content->getModel() .
- " (" . ContentHandler::getContentModelName( $content->getModel() ). ")" );
+ " uses content model " . $content->getModel() . ")" );
}
}
} else {
$this->setWarning( "Template expansion is supported for wikitext only, " .
$title->getPrefixedDBkey() .
- " uses content model #" . $content->getModel() .
- " (" . ContentHandler::getContentModelName( $content->getModel() ). ")" );
+ " uses content model " . $content->getModel() . ")" );
$text = false;
}
if ( !$content->isSupportedFormat( $format ) ) {
$model = $content->getModel();
- $formatName = ContentHandler::getContentFormatMimeType( $format );
- $modelName = ContentHandler::getContentModelName( $model );
$name = $title->getPrefixedDBkey();
- $this->dieUsage( "The requested format #{$this->contentFormat} ($formatName) is not supported for content model #$model ($modelName) used by $name", 'badformat' );
+ $this->dieUsage( "The requested format {$this->contentFormat} is not supported for content model $model used by $name", 'badformat' );
}
$text = $content->serialize( $format );
- $vals['contentformat'] = ContentHandler::getContentFormatMimeType( $format );
+ $vals['contentformat'] = $format;
}
if ( $text !== false ) {
$model = $title->getContentModel();
if ( $this->contentFormat && !ContentHandler::getForModelID( $model )->isSupportedFormat( $this->contentFormat ) ) {
- $formatName = ContentHandler::getContentFormatMimeType( $this->contentFormat );
- $modelName = ContentHandler::getContentModelName( $model );
$name = $title->getPrefixedDBkey();
- $this->dieUsage( "The requested format #{$this->contentFormat} ($formatName) is not supported for content model #$model ($modelName) used by $name", 'badformat' );
+ $this->dieUsage( "The requested format {$this->contentFormat} is not supported for content model $model used by $name", 'badformat' );
}
$difftocontent = ContentHandler::makeContent( $this->difftotext, $title, $model, $this->contentFormat );
'diffto' => null,
'difftotext' => null,
'contentformat' => array(
- ApiBase::PARAM_TYPE => array_values( $GLOBALS[ 'wgContentFormatMimeTypes' ] ),
+ ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
ApiBase::PARAM_DFLT => null
),
);
'length' => intval( $row->page_len ),
'redirect' => intval( $row->page_is_redirect ),
'revision' => intval( $row->page_latest ),
- 'model' => !empty( $row->page_content_model ) ? intval( $row->page_content_model ) : null,
+ 'model' => !empty( $row->page_content_model ) ? strval( $row->page_content_model ) : null,
);
}
'yourdiff' => 'Differences',
'copyrightwarning' => "Please note that all contributions to {{SITENAME}} are considered to be released under the $2 (see $1 for details).
If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.<br />
-You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
+You are also promising us that you wrote this yourself, or copied editpageit from a public domain or similar free resource.
'''Do not submit copyrighted work without permission!'''",
'copyrightwarning2' => "Please note that all contributions to {{SITENAME}} may be edited, altered, or removed by other contributors.
If you do not want your writing to be edited mercilessly, then do not submit it here.<br />
'addsection-preload' => '', # do not translate or duplicate this message to other languages
'addsection-editintro' => '', # do not translate or duplicate this message to other languages
'defaultmessagetext' => 'Default message text',
+'invalid-content-data' => 'Invalid content data',
# Parser/template warnings
'expensive-parserfunction-warning' => "'''Warning:''' This page contains too many expensive parser function calls.
'moveddeleted-notice' => 'Shown on top of a deleted page in normal view modus ([http://translatewiki.net/wiki/Test example]).',
'edit-conflict' => "An 'Edit conflict' happens when more than one edit is being made to a page at the same time. This would usually be caused by separate individuals working on the same page. However, if the system is slow, several edits from one individual could back up and attempt to apply simultaneously - causing the conflict.",
'defaultmessagetext' => 'Caption above the default message text shown on the left-hand side of a diff displayed after clicking “Show changes” when creating a new page in the MediaWiki: namespace',
+'invalid-content-data' => 'Error message indicating that the page\'s content can not be saved because it is invalid. This may occurr for some non-text content types.',
# Parser/template warnings
'expensive-parserfunction-warning' => 'On some (expensive) [[MetaWikipedia:Help:ParserFunctions|parser functions]] (e.g. <code><nowiki>{{#ifexist:}}</nowiki></code>) there is a limit of how many times it may be used. This is an error message shown when the limit is exceeded.
ALTER TABLE /*$wgDBprefix*/archive
- ADD ar_content_format int unsigned DEFAULT NULL;
+ ADD ar_content_format varbinary(64) DEFAULT NULL;
ALTER TABLE /*$wgDBprefix*/archive
- ADD ar_content_model int unsigned DEFAULT NULL;
+ ADD ar_content_model varbinary(32) DEFAULT NULL;
ALTER TABLE /*$wgDBprefix*/page
- ADD page_content_model int unsigned DEFAULT NULL;
+ ADD page_content_model varbinary(32) DEFAULT NULL;
ALTER TABLE /*$wgDBprefix*/revision
- ADD rev_content_format int unsigned DEFAULT NULL;
+ ADD rev_content_format varbinary(64) DEFAULT NULL;
ALTER TABLE /*$wgDBprefix*/revision
- ADD rev_content_model int unsigned DEFAULT NULL;
+ ADD rev_content_model varbinary(32) DEFAULT NULL;
--- /dev/null
+ALTER TABLE /*$wgDBprefix*/archive DROP COLUMN ar_content_model;
+ALTER TABLE /*$wgDBprefix*/archive DROP COLUMN ar_content_format;
+
+ALTER TABLE /*$wgDBprefix*/revision DROP COLUMN rev_content_model;
+ALTER TABLE /*$wgDBprefix*/revision DROP COLUMN rev_content_format;
+
+ALTER TABLE /*$wgDBprefix*/page DROP COLUMN page_content_model;
$wgExtraNamespaces[ 12312 ] = 'Dummy';
$wgExtraNamespaces[ 12313 ] = 'Dummy_talk';
- $wgNamespaceContentModels[ 12312 ] = 999999;
- $wgContentHandlers[ 999999 ] = 'DummyContentHandlerForTesting';
+ $wgNamespaceContentModels[ 12312 ] = "testing";
+ $wgContentHandlers[ "testing" ] = 'DummyContentHandlerForTesting';
MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
$wgContLang->resetNamespaces(); # reset namespace cache
unset( $wgExtraNamespaces[ 12313 ] );
unset( $wgNamespaceContentModels[ 12312 ] );
- unset( $wgContentHandlers[ 999999 ] );
+ unset( $wgContentHandlers[ "testing" ] );
MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
$wgContLang->resetNamespaces(); # reset namespace cache
$this->assertEquals( $expectedContentModel, $handler->getModelID() );
}
- public function dataGetContentFormatMimeType( ) {
+ public function dataGetLocalizedName() {
return array(
- array( 0, null ),
array( null, null ),
- array( 99887766, null ),
-
- array( CONTENT_FORMAT_WIKITEXT, 'text/x-wiki' ),
- array( CONTENT_FORMAT_JAVASCRIPT, 'text/javascript' ),
- array( CONTENT_FORMAT_CSS, 'text/css' ),
- array( CONTENT_FORMAT_JSON, 'application/json' ),
- array( CONTENT_FORMAT_XML, 'application/xml' ),
- array( CONTENT_FORMAT_SERIALIZED, 'application/vnd.php.serialized' ),
- );
- }
-
- /**
- * @dataProvider dataGetContentFormatMimeType
- */
- public function testGetContentFormatMimeType( $id, $expectedMime ) {
- $mime = ContentHandler::getContentFormatMimeType( $id );
-
- $this->assertEquals( $expectedMime, $mime );
- }
-
- public function dataGetContentFormatID( ) {
- return array(
- array( '', null ),
- array( 'foo', null ),
- array( null, null ),
-
- array( 'text/x-wiki', CONTENT_FORMAT_WIKITEXT ),
- array( 'text/javascript', CONTENT_FORMAT_JAVASCRIPT ),
- array( 'text/css', CONTENT_FORMAT_CSS ),
- array( 'application/json', CONTENT_FORMAT_JSON ),
- array( 'application/xml', CONTENT_FORMAT_XML ),
- array( 'application/vnd.php.serialized', CONTENT_FORMAT_SERIALIZED ),
- );
- }
-
- /**
- * @dataProvider dataGetContentFormatID
- */
- public function testGetContentFormatID( $mime, $expectedId ) {
- $id = ContentHandler::getContentFormatID( $mime );
-
- $this->assertEquals( $expectedId, $id );
- }
-
- public function dataGetLocalizedNameName() {
- return array(
- array( 0, null ),
- array( null, null ),
- array( 99887766, null ),
+ array( "xyzzy", null ),
array( CONTENT_MODEL_JAVASCRIPT, '/javascript/i' ), //XXX: depends on content language
);
}
/**
- * @dataProvider dataGetLocalizedNameName
+ * @dataProvider dataGetLocalizedName
*/
public function testGetLocalizedName( $id, $expected ) {
- try{
- $name = ContentHandler::getLocalizedName( $id );
+ $name = ContentHandler::getLocalizedName( $id );
- if ( !$expected ) $this->fail("should not have a name for content id #$id");
-
- $this->assertNotNull( $name, "no name found for content model #$id" );
+ if ( $expected ) {
+ $this->assertNotNull( $name, "no name found for content model $id" );
$this->assertTrue( preg_match( $expected, $name ) > 0 , "content model name for #$id did not match pattern $expected" );
- } catch (MWException $e) {
- if ( $expected ) $this->fail("failed to get name for content id #$id");
+ } else {
+ $this->assertEquals( $id, $name, "localization of unknown model $id should have fallen back to use the model id directly." );
}
}
- public function dataGetContentModelName() {
+ public function dataGetPageLanguage() {
+ global $wgLanguageCode;
+
return array(
- array( 0, null ),
- array( null, null ),
- array( 99887766, null ),
+ array( "Main", $wgLanguageCode ),
+ array( "Dummy:Foo", $wgLanguageCode ),
+ array( "MediaWiki:common.js", 'en' ),
+ array( "User:Foo/common.js", 'en' ),
+ array( "MediaWiki:common.css", 'en' ),
+ array( "User:Foo/common.css", 'en' ),
+ array( "User:Foo", $wgLanguageCode ),
array( CONTENT_MODEL_JAVASCRIPT, 'javascript' ),
);
}
/**
- * @dataProvider dataGetContentModelName
+ * @dataProvider dataGetPageLanguage
*/
- public function testGetContentModelName( $id, $expected ) {
- try {
- $name = ContentHandler::getContentModelName( $id );
-
- if ( !$expected ) $this->fail("should not have a name for content id #$id");
-
- $this->assertNotNull( $name, "no name found for content model #$id" );
- $this->assertEquals( $expected, $name);
- } catch (MWException $e) {
- if ( $expected ) $this->fail("failed to get name for content id #$id");
+ public function testGetPageLanguage( $title, $expected ) {
+ if ( is_string( $title ) ) {
+ $title = Title::newFromText( $title );
}
- }
- /**
- * @dataProvider dataGetContentModelName
- */
- public function testGetModelName( $id, $expected ) {
- try {
- $handler = ContentHandler::getForModelID( $id );
- $name = $handler->getModelName();
+ $expected = wfGetLangObj( $expected );
- if ( !$expected ) $this->fail("should not have a name for content id #$id");
+ $handler = ContentHandler::getForTitle( $title );
+ $lang = $handler->getPageLanguage( $title );
- $this->assertNotNull( $name, "no name found for content model #$id" );
- $this->assertEquals( $expected, $name);
- } catch (MWException $e) {
- if ( $expected ) $this->fail("failed to get name for content id #$id");
- }
+ $this->assertEquals( $expected->getCode(), $lang->getCode() );
}
public function testGetContentText_Null( ) {
return array(
array( 'hallo', 'Test', null, null, CONTENT_MODEL_WIKITEXT, 'hallo', false ),
array( 'hallo', 'MediaWiki:Test.js', null, null, CONTENT_MODEL_JAVASCRIPT, 'hallo', false ),
- array( serialize('hallo'), 'Dummy:Test', null, null, 999999, 'hallo', false ),
+ array( serialize('hallo'), 'Dummy:Test', null, null, "testing", 'hallo', false ),
array( 'hallo', 'Test', null, CONTENT_FORMAT_WIKITEXT, CONTENT_MODEL_WIKITEXT, 'hallo', false ),
array( 'hallo', 'MediaWiki:Test.js', null, CONTENT_FORMAT_JAVASCRIPT, CONTENT_MODEL_JAVASCRIPT, 'hallo', false ),
- array( serialize('hallo'), 'Dummy:Test', null, 999999, 999999, 'hallo', false ),
+ array( serialize('hallo'), 'Dummy:Test', null, "testing", "testing", 'hallo', false ),
array( 'hallo', 'Test', CONTENT_MODEL_CSS, null, CONTENT_MODEL_CSS, 'hallo', false ),
array( 'hallo', 'MediaWiki:Test.js', CONTENT_MODEL_CSS, null, CONTENT_MODEL_CSS, 'hallo', false ),
array( serialize('hallo'), 'Dummy:Test', CONTENT_MODEL_CSS, null, CONTENT_MODEL_CSS, serialize('hallo'), false ),
- array( 'hallo', 'Test', CONTENT_MODEL_WIKITEXT, 999999, null, null, true ),
- array( 'hallo', 'MediaWiki:Test.js', CONTENT_MODEL_CSS, 999999, null, null, true ),
- array( 'hallo', 'Dummy:Test', CONTENT_MODEL_JAVASCRIPT, 999999, null, null, true ),
+ array( 'hallo', 'Test', CONTENT_MODEL_WIKITEXT, "testing", null, null, true ),
+ array( 'hallo', 'MediaWiki:Test.js', CONTENT_MODEL_CSS, "testing", null, null, true ),
+ array( 'hallo', 'Dummy:Test', CONTENT_MODEL_JAVASCRIPT, "testing", null, null, true ),
);
}
class DummyContentHandlerForTesting extends ContentHandler {
public function __construct( $dataModel ) {
- parent::__construct( $dataModel, array( 999999 ) );
+ parent::__construct( $dataModel, array( "testing" ) );
}
/**
class DummyContentForTesting extends AbstractContent {
public function __construct( $data ) {
- parent::__construct( 999999 );
+ parent::__construct( "testing" );
$this->data = $data;
}
$wgExtraNamespaces[ 12312 ] = 'Dummy';
$wgExtraNamespaces[ 12313 ] = 'Dummy_talk';
- $wgNamespaceContentModels[ 12312 ] = 999999;
- $wgContentHandlers[ 999999 ] = 'DummyContentHandlerForTesting';
+ $wgNamespaceContentModels[ 12312 ] = "testing";
+ $wgContentHandlers[ "testing" ] = 'DummyContentHandlerForTesting';
MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
$wgContLang->resetNamespaces(); # reset namespace cache
return array(
array( 'hello world', 'Hello', null, null, CONTENT_MODEL_WIKITEXT ),
array( 'hello world', 'User:hello/there.css', null, null, CONTENT_MODEL_CSS ),
- array( serialize('hello world'), 'Dummy:Hello', null, null, 999999 ),
+ array( serialize('hello world'), 'Dummy:Hello', null, null, "testing" ),
);
}
array( 'hello world', 'Hello', null, null, CONTENT_FORMAT_WIKITEXT ),
array( 'hello world', 'Hello', CONTENT_MODEL_CSS, null, CONTENT_FORMAT_CSS ),
array( 'hello world', 'User:hello/there.css', null, null, CONTENT_FORMAT_CSS ),
- array( serialize('hello world'), 'Dummy:Hello', null, null, 999999 ),
+ array( serialize('hello world'), 'Dummy:Hello', null, null, "testing" ),
);
}
function dataGetContent() {
return array(
array( 'hello world', 'Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ),
- array( serialize('hello world'), 'Hello', 999999, null, Revision::FOR_PUBLIC, serialize('hello world') ),
+ array( serialize('hello world'), 'Hello', "testing", null, Revision::FOR_PUBLIC, serialize('hello world') ),
array( serialize('hello world'), 'Dummy:Hello', null, null, Revision::FOR_PUBLIC, serialize('hello world') ),
);
}
function dataGetText() {
return array(
array( 'hello world', 'Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ),
- array( serialize('hello world'), 'Hello', 999999, null, Revision::FOR_PUBLIC, null ),
+ array( serialize('hello world'), 'Hello', "testing", null, Revision::FOR_PUBLIC, null ),
array( serialize('hello world'), 'Dummy:Hello', null, null, Revision::FOR_PUBLIC, null ),
);
}
public function dataGetSize( ) {
return array(
array( "hello world.", null, 12 ),
- array( serialize( "hello world." ), 999999, 12 ),
+ array( serialize( "hello world." ), "testing", 12 ),
);
}
public function dataGetSha1( ) {
return array(
array( "hello world.", null, Revision::base36Sha1( "hello world." ) ),
- array( serialize( "hello world." ), 999999, Revision::base36Sha1( serialize( "hello world." ) ) ),
+ array( serialize( "hello world." ), "testing", Revision::base36Sha1( serialize( "hello world." ) ) ),
);
}
--- /dev/null
+<?php
+
+/**
+ * @group API
+ * @group Database
+ */
+class ApiEditPageTest extends ApiTestCase {
+
+ function setUp() {
+ parent::setUp();
+ $this->doLogin();
+ }
+
+ function getTokens() {
+ return $this->getTokenList( self::$users['sysop'] );
+ }
+
+ function testEdit() {
+ $name = 'ApiEditPageTest_testEdit';
+
+ $tokenData = $this->getTokens();
+
+ if( !isset( $tokenData[0]['query']['pages'] ) ) {
+ $this->markTestIncomplete( "No edit token found" );
+ }
+
+ $keys = array_keys( $tokenData[0]['query']['pages'] );
+ $key = array_pop( $keys );
+ $pageinfo = $tokenData[0]['query']['pages'][$key];
+ $session = $tokenData[2];
+
+ // -----------------------------------------------------------------------
+
+ $data = $this->doApiRequest( array(
+ 'action' => 'edit',
+ 'title' => $name,
+ 'text' => 'some text',
+ 'token' => $pageinfo['edittoken'] ),
+ $session,
+ false,
+ self::$users['sysop']->user );
+
+ $this->assertArrayHasKey( 'edit', $data[0] );
+ $this->assertArrayHasKey( 'result', $data[0]['edit'] );
+ $this->assertEquals( 'Success', $data[0]['edit']['result'] );
+
+ $this->assertArrayHasKey( 'new', $data[0]['edit'] );
+ $this->assertArrayNotHasKey( 'nochange', $data[0]['edit'] );
+
+ $this->assertArrayHasKey( 'pageid', $data[0]['edit'] );
+ $this->assertArrayHasKey( 'contentmodel', $data[0]['edit'] );
+ $this->assertEquals( CONTENT_MODEL_WIKITEXT, $data[0]['edit']['contentmodel'] );
+
+ // -----------------------------------------------------------------------
+ $data = $this->doApiRequest( array(
+ 'action' => 'edit',
+ 'title' => $name,
+ 'text' => 'some text',
+ 'token' => $pageinfo['edittoken'] ),
+ $session,
+ false,
+ self::$users['sysop']->user );
+
+ $this->assertEquals( 'Success', $data[0]['edit']['result'] );
+
+ $this->assertArrayNotHasKey( 'new', $data[0]['edit'] );
+ $this->assertArrayHasKey( 'nochange', $data[0]['edit'] );
+
+ // -----------------------------------------------------------------------
+ $data = $this->doApiRequest( array(
+ 'action' => 'edit',
+ 'title' => $name,
+ 'text' => 'different text',
+ 'token' => $pageinfo['edittoken'] ),
+ $session,
+ false,
+ self::$users['sysop']->user );
+
+ $this->assertEquals( 'Success', $data[0]['edit']['result'] );
+
+ $this->assertArrayNotHasKey( 'new', $data[0]['edit'] );
+ $this->assertArrayNotHasKey( 'nochange', $data[0]['edit'] );
+
+ $this->assertArrayHasKey( 'oldrevid', $data[0]['edit'] );
+ $this->assertArrayHasKey( 'newrevid', $data[0]['edit'] );
+ $this->assertTrue( $data[0]['edit']['newrevid'] !== $data[0]['edit']['oldrevid'], "revision id should change after edit" );
+ }
+
+ function testEditAppend() {
+ $this->markTestIncomplete( "not yet implemented" );
+ }
+
+ function testEditSection() {
+ $this->markTestIncomplete( "not yet implemented" );
+ }
+
+ function testUndo() {
+ $this->markTestIncomplete( "not yet implemented" );
+ }
+
+ function testEditNonText() {
+ $this->markTestIncomplete( "not yet implemented" );
+ }
+}
* @param $text_sha1 string: the base36 SHA-1 of the revision's text
* @param $text string|false: (optional) The revision's string, or false to check for a
* revision stub
- * @param $model int: the expected content model id (default: CONTENT_MODEL_WIKITEXT)
- * @param $format int: the expected format model id (default: CONTENT_FORMAT_WIKITEXT)
+ * @param $model String: the expected content model id (default: CONTENT_MODEL_WIKITEXT)
+ * @param $format String: the expected format model id (default: CONTENT_FORMAT_WIKITEXT)
* @param $parentid int|false: (optional) id of the parent revision
*/
protected function assertRevision( $id, $summary, $text_id, $text_bytes, $text_sha1, $text = false, $parentid = false,
</contributor>
<comment>BackupDumperTestP1Summary1</comment>
<sha1>0bolhl6ol7i6x0e7yq91gxgaan39j87</sha1>
- <model name="wikitext">1</model>
- <format mime="text/x-wiki">1</format>
+ <model>wikitext</model>
+ <format>text/x-wiki</format>
<text id="' . $this->textId1_1 . '" bytes="23" />
</revision>
</page>
</contributor>
<comment>BackupDumperTestP2Summary1</comment>
<sha1>jprywrymfhysqllua29tj3sc7z39dl2</sha1>
- <model name="wikitext">1</model>
- <format mime="text/x-wiki">1</format>
+ <model>wikitext</model>
+ <format>text/x-wiki</format>
<text id="' . $this->textId2_1 . '" bytes="23" />
</revision>
<revision>
</contributor>
<comment>BackupDumperTestP2Summary2</comment>
<sha1>b7vj5ks32po5m1z1t1br4o7scdwwy95</sha1>
- <model name="wikitext">1</model>
- <format mime="text/x-wiki">1</format>
+ <model>wikitext</model>
+ <format>text/x-wiki</format>
<text id="' . $this->textId2_2 . '" bytes="23" />
</revision>
<revision>
</contributor>
<comment>BackupDumperTestP2Summary3</comment>
<sha1>jfunqmh1ssfb8rs43r19w98k28gg56r</sha1>
- <model name="wikitext">1</model>
- <format mime="text/x-wiki">1</format>
+ <model>wikitext</model>
+ <format>text/x-wiki</format>
<text id="' . $this->textId2_3 . '" bytes="23" />
</revision>
<revision>
</contributor>
<comment>BackupDumperTestP2Summary4 extra</comment>
<sha1>6o1ciaxa6pybnqprmungwofc4lv00wv</sha1>
- <model name="wikitext">1</model>
- <format mime="text/x-wiki">1</format>
+ <model>wikitext</model>
+ <format>text/x-wiki</format>
<text id="' . $this->textId2_4 . '" bytes="44" />
</revision>
</page>
</contributor>
<comment>Talk BackupDumperTestP1 Summary1</comment>
<sha1>nktofwzd0tl192k3zfepmlzxoax1lpe</sha1>
- <model name="wikitext">1</model>
- <format mime="text/x-wiki">1</format>
+ <model>wikitext</model>
+ <format>text/x-wiki</format>
<text id="' . $this->textId4_1 . '" bytes="35" />
</revision>
</page>