baby steps towards editing structured data
authorDaniel Kinzler <daniel.kinzler@wikimedia.de>
Fri, 23 Mar 2012 16:55:15 +0000 (16:55 +0000)
committerDaniel Kinzler <daniel.kinzler@wikimedia.de>
Wed, 4 Apr 2012 17:59:09 +0000 (19:59 +0200)
includes/ContentHandler.php
includes/EditPage.php
includes/Revision.php
includes/WikiPage.php

index 67bc812..496d7c9 100644 (file)
@@ -304,84 +304,91 @@ abstract class ContentHandler {
     public function getAutoDeleteReason( Title $title, &$hasHistory ) {
         global $wgContLang;
 
-        $dbw = wfGetDB( DB_MASTER );
+        try {
+            $dbw = wfGetDB( DB_MASTER );
 
-        // Get the last revision
-        $rev = Revision::newFromTitle( $title );
+            // Get the last revision
+            $rev = Revision::newFromTitle( $title );
 
-        if ( is_null( $rev ) ) {
-            return false;
-        }
+            if ( is_null( $rev ) ) {
+                return false;
+            }
 
-        // Get the article's contents
-        $content = $rev->getContent();
-        $blank = false;
+            // Get the article's contents
+            $content = $rev->getContent();
+            $blank = false;
 
-        // If the page is blank, use the text from the previous revision,
-        // which can only be blank if there's a move/import/protect dummy revision involved
-        if ( $content->getSize() == 0 ) {
-            $prev = $rev->getPrevious();
+            // If the page is blank, use the text from the previous revision,
+            // which can only be blank if there's a move/import/protect dummy revision involved
+            if ( $content->getSize() == 0 ) {
+                $prev = $rev->getPrevious();
 
-            if ( $prev )       {
-                $content = $rev->getContent();
-                $blank = true;
+                if ( $prev )   {
+                    $content = $rev->getContent();
+                    $blank = true;
+                }
             }
-        }
 
-        // Find out if there was only one contributor
-        // Only scan the last 20 revisions
-        $res = $dbw->select( 'revision', 'rev_user_text',
-            array( 'rev_page' => $title->getArticleID(), $dbw->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' ),
-            __METHOD__,
-            array( 'LIMIT' => 20 )
-        );
-
-        if ( $res === false ) {
-            // This page has no revisions, which is very weird
-            return false;
-        }
-
-        $hasHistory = ( $res->numRows() > 1 );
-        $row = $dbw->fetchObject( $res );
+            // Find out if there was only one contributor
+            // Only scan the last 20 revisions
+            $res = $dbw->select( 'revision', 'rev_user_text',
+                array( 'rev_page' => $title->getArticleID(), $dbw->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' ),
+                __METHOD__,
+                array( 'LIMIT' => 20 )
+            );
+
+            if ( $res === false ) {
+                // This page has no revisions, which is very weird
+                return false;
+            }
 
-        if ( $row ) { // $row is false if the only contributor is hidden
-            $onlyAuthor = $row->rev_user_text;
-            // Try to find a second contributor
-            foreach ( $res as $row ) {
-                if ( $row->rev_user_text != $onlyAuthor ) { // Bug 22999
-                    $onlyAuthor = false;
-                    break;
+            $hasHistory = ( $res->numRows() > 1 );
+            $row = $dbw->fetchObject( $res );
+
+            if ( $row ) { // $row is false if the only contributor is hidden
+                $onlyAuthor = $row->rev_user_text;
+                // Try to find a second contributor
+                foreach ( $res as $row ) {
+                    if ( $row->rev_user_text != $onlyAuthor ) { // Bug 22999
+                        $onlyAuthor = false;
+                        break;
+                    }
                 }
+            } else {
+                $onlyAuthor = false;
             }
-        } else {
-            $onlyAuthor = false;
-        }
 
-        // Generate the summary with a '$1' placeholder
-        if ( $blank ) {
-            // The current revision is blank and the one before is also
-            // blank. It's just not our lucky day
-            $reason = wfMsgForContent( 'exbeforeblank', '$1' );
-        } else {
-            if ( $onlyAuthor ) {
-                $reason = wfMsgForContent( 'excontentauthor', '$1', $onlyAuthor );
+            // Generate the summary with a '$1' placeholder
+            if ( $blank ) {
+                // The current revision is blank and the one before is also
+                // blank. It's just not our lucky day
+                $reason = wfMsgForContent( 'exbeforeblank', '$1' );
             } else {
-                $reason = wfMsgForContent( 'excontent', '$1' );
+                if ( $onlyAuthor ) {
+                    $reason = wfMsgForContent( 'excontentauthor', '$1', $onlyAuthor );
+                } else {
+                    $reason = wfMsgForContent( 'excontent', '$1' );
+                }
             }
-        }
 
-        if ( $reason == '-' ) {
-            // Allow these UI messages to be blanked out cleanly
-            return '';
-        }
+            if ( $reason == '-' ) {
+                // Allow these UI messages to be blanked out cleanly
+                return '';
+            }
+
+            // Max content length = max comment length - length of the comment (excl. $1)
+            $text = $content->getTextForSummary( 255 - ( strlen( $reason ) - 2 ) );
 
-        // Max content length = max comment length - length of the comment (excl. $1)
-        $text = $content->getTextForSummary( 255 - ( strlen( $reason ) - 2 ) );
+            // Now replace the '$1' placeholder
+            $reason = str_replace( '$1', $text, $reason );
 
-        // Now replace the '$1' placeholder
-        $reason = str_replace( '$1', $text, $reason );
+            return $reason;
+        } catch (MWException $e) {
+            # if a page is horribly broken, we still want to be able to delete it. so be lenient about errors here.
+            wfDebug("Error while building auto delete summary: $e");
+        }
 
-        return $reason;
+        return '';
     }
 
     /**
index 054c2ef..aff1ea9 100644 (file)
@@ -706,6 +706,9 @@ class EditPage {
                $this->content_model = $request->getText( 'model', $content_handler->getModelName() ); #may be overridden by revision
         $this->content_format = $request->getText( 'format', $content_handler->getDefaultFormat() ); #may be overridden by revision
 
+        #TODO: check if the desired model is allowed in this namespace, and if a transition from the page's current model to the new model is allowed
+        #TODO: check if the desired content model supports the given content format!
+
                $this->live = $request->getCheck( 'live' );
                $this->editintro = $request->getText( 'editintro',
                        // Custom edit intro for new sections
@@ -920,7 +923,7 @@ class EditPage {
         */
        private function getCurrentContent() {
         $rev = $this->mArticle->getRevision();
-               $content = $rev->getContent( Revision::RAW );
+               $content = $rev ? $rev->getContent( Revision::RAW ) : null;
 
                if ( $content  === false || $content === null ) {
             if ( !$this->content_model ) $this->content_model = $this->getTitle()->getContentModelName();
@@ -1520,7 +1523,7 @@ class EditPage {
                        ( ( $this->minoredit && !$this->isNew ) ? EDIT_MINOR : 0 ) |
                        ( $bot ? EDIT_FORCE_BOT : 0 );
 
-               $doEditStatus = $this->mArticle->doEditContent( $content, $this->summary, $flags );
+               $doEditStatus = $this->mArticle->doEditContent( $content, $this->summary, $flags, false, null, $this->content_format );
 
                if ( $doEditStatus->isOK() ) {
                        $result['redirect'] = $content->isRedirect();
@@ -1918,6 +1921,9 @@ class EditPage {
 
                $wgOut->addHTML( Html::hidden( 'oldid', $this->oldid ) );
 
+        $wgOut->addHTML( Html::hidden( 'format', $this->content_format ) );
+        $wgOut->addHTML( Html::hidden( 'model', $this->content_model ) );
+
                if ( $this->section == 'new' ) {
                        $this->showSummaryInput( true, $this->summary );
                        $wgOut->addHTML( $this->getSummaryPreview( true, $this->summary ) );
@@ -1948,6 +1954,9 @@ class EditPage {
 
                $wgOut->addWikiText( $this->getCopywarn() );
 
+        $wgOut->addHTML( Html::element( 'p', null, "model: " . $this->content_model ) ); #FIXME: content handler debug stuff, DELETE!
+        $wgOut->addHTML( Html::element( 'p', null, "format: " . $this->content_format ) ); #FIXME: content handler debug stuff, DELETE!
+
                $wgOut->addHTML( $this->editFormTextAfterWarn );
 
                $this->showStandardInputs();
@@ -2692,8 +2701,7 @@ HTML
                # don't parse non-wikitext pages, show message about preview
                # XXX: stupid php bug won't let us use $this->getContextTitle()->isCssJsSubpage() here -- This note has been there since r3530. Sure the bug was fixed time ago?
 
-        #FIXME: get appropriate content handler!
-               if ( $this->isCssJsSubpage || !$this->mTitle->isWikitextPage() ) {
+               if ( $this->isCssJsSubpage || $this->mTitle->isCssOrJsPage() ) { #TODO: kill all special case handling for CSS/JS content!
                        if( $this->mTitle->isCssJsSubpage() ) {
                                $level = 'user';
                        } elseif( $this->mTitle->isCssOrJsPage() ) {
@@ -2715,30 +2723,39 @@ HTML
                                } else {
                                        throw new MWException( 'A CSS/JS (sub)page but which is not css nor js!' );
                                }
-                       }
+                       } #FIXME: else $previewtext is undefined!
 
                        $parserOutput = $wgParser->parse( $previewtext, $this->mTitle, $parserOptions );
                        $previewHTML = $parserOutput->mText;
-                       $previewHTML .= "<pre class=\"$class\" dir=\"ltr\">\n" . htmlspecialchars( $this->textbox1 ) . "\n</pre>\n";
+                       $previewHTML .= "<pre class=\"$class\" dir=\"ltr\">\n" . htmlspecialchars( $this->textbox1 ) . "\n</pre>\n"; #FIXME: use content object!
                } else {
                        $rt = Title::newFromRedirectArray( $this->textbox1 );
                        if ( $rt ) {
                                $previewHTML = $this->mArticle->viewRedirect( $rt, false );
                        } else {
-                               $toparse = $this->textbox1;
+                               $content = ContentHandler::makeContent( $this->textbox1, $this->getTitle(), $this->content_model, $this->content_format );
 
                                # If we're adding a comment, we need to show the
                                # summary as the headline
                                if ( $this->section == "new" && $this->summary != "" ) {
-                                       $toparse = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->summary ) . "\n\n" . $toparse;
+                    $content = $content->addSectionHeader( $this->summary );
                                }
 
+                $toparse_orig = $content->serialize( $this->content_format );
+                $toparse = $toparse_orig;
                                wfRunHooks( 'EditPageGetPreviewText', array( $this, &$toparse ) );
 
+                if ( $toparse !== $toparse_orig ) {
+                    #hook changed the text, create new Content object
+                    $content = ContentHandler::makeContent( $toparse, $this->getTitle(), $this->content_model, $this->content_format );
+                }
+
+                wfRunHooks( 'EditPageGetPreviewContent', array( $this, &$content ) ); # FIXME: document new hook
+
                                $parserOptions->enableLimitReport();
 
-                               $toparse = $wgParser->preSaveTransform( $toparse, $this->mTitle, $wgUser, $parserOptions );
-                               $parserOutput = $wgParser->parse( $toparse, $this->mTitle, $parserOptions );
+                               $content = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
+                               $parserOutput = $content->getParserOutput( $this->mTitle, null, $parserOptions );
 
                                $previewHTML = $parserOutput->getText();
                                $this->mParserOutput = $parserOutput;
index 4c62d04..1e36e34 100644 (file)
@@ -479,13 +479,7 @@ class Revision {
                        $this->mSha1      = isset( $row['sha1']  )      ? strval( $row['sha1']  )      : null;
 
             $this->mContentModelName = isset( $row['content_model']  )  ? strval( $row['content_model'] ) : null;
-            $this->mContentFormat      = isset( $row['content_format']  )   ? strval( $row['content_format'] ) : null;
-
-            if( !isset( $row->rev_content_format ) || is_null( $row->rev_content_format ) ) {
-                $this->mContentFormat = null; # determine on demand if needed
-            } else {
-                $this->mContentFormat = $row->rev_content_format;
-            }
+            $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;
@@ -843,7 +837,7 @@ class Revision {
                 $this->mText = $this->loadText();
             }
 
-            $this->mContent = $handler->unserialize( $this->mText, $title, $format );
+            $this->mContent = is_null( $this->mText ) ? null : $handler->unserialize( $this->mText, $format );
         }
 
         return $this->mContent;
@@ -1104,28 +1098,29 @@ class Revision {
                $rev_id = isset( $this->mId )
                        ? $this->mId
                        : $dbw->nextSequenceValue( 'revision_rev_id_seq' );
-               $dbw->insert( 'revision',
-                       array(
-                               'rev_id'         => $rev_id,
-                               'rev_page'       => $this->mPage,
-                               'rev_text_id'    => $this->mTextId,
-                               'rev_comment'    => $this->mComment,
-                               'rev_minor_edit' => $this->mMinorEdit ? 1 : 0,
-                               'rev_user'       => $this->mUser,
-                               'rev_user_text'  => $this->mUserText,
-                               'rev_timestamp'  => $dbw->timestamp( $this->mTimestamp ),
-                               'rev_deleted'    => $this->mDeleted,
-                               'rev_len'        => $this->mSize,
-                               'rev_parent_id'  => is_null( $this->mParentId )
-                                       ? $this->getPreviousRevisionId( $dbw )
-                                       : $this->mParentId,
-                               'rev_sha1'       => is_null( $this->mSha1 )
-                                       ? Revision::base36Sha1( $this->mText )
-                                       : $this->mSha1,
-                'rev_content_model'       => $this->getContentModelName(),
-                'rev_content_format'        => $this->getContentFormat(),
-                       ), __METHOD__
-               );
+
+        $row = array(
+            'rev_id'         => $rev_id,
+            'rev_page'       => $this->mPage,
+            'rev_text_id'    => $this->mTextId,
+            'rev_comment'    => $this->mComment,
+            'rev_minor_edit' => $this->mMinorEdit ? 1 : 0,
+            'rev_user'       => $this->mUser,
+            'rev_user_text'  => $this->mUserText,
+            'rev_timestamp'  => $dbw->timestamp( $this->mTimestamp ),
+            'rev_deleted'    => $this->mDeleted,
+            'rev_len'        => $this->mSize,
+            'rev_parent_id'  => is_null( $this->mParentId )
+                ? $this->getPreviousRevisionId( $dbw )
+                : $this->mParentId,
+            'rev_sha1'       => is_null( $this->mSha1 )
+                ? Revision::base36Sha1( $this->mText )
+                : $this->mSha1,
+            'rev_content_model'       => $this->getContentModelName(),
+            'rev_content_format'        => $this->getContentFormat(),
+        );
+
+               $dbw->insert( 'revision', $row, __METHOD__ );
 
                $this->mId = !is_null( $rev_id ) ? $rev_id : $dbw->insertId();
 
index d2b19b2..adf72f8 100644 (file)
@@ -1397,7 +1397,9 @@ class WikiPage extends Page {
                                'parent_id'  => $oldid,
                                'user'       => $user->getId(),
                                'user_text'  => $user->getName(),
-                               'timestamp'  => $now
+                               'timestamp'  => $now,
+                'content_model' => $content->getModelName(),
+                'content_format' => $serialisation_format,
                        ) );
 
                        $changed = !$content->equals( $old_content );
@@ -1502,7 +1504,9 @@ class WikiPage extends Page {
                 'len'        => $newsize,
                                'user'       => $user->getId(),
                                'user_text'  => $user->getName(),
-                               'timestamp'  => $now
+                               'timestamp'  => $now,
+                'content_model' => $content->getModelName(),
+                'content_format' => $serialisation_format,
                        ) );
                        $revisionId = $revision->insertOn( $dbw );