baby steps towards editing structured data
[lhc/web/wiklou.git] / includes / ContentHandler.php
index 39f9fcd..496d7c9 100644 (file)
  */
 abstract class ContentHandler {
 
-    public static function getContentText( Content $content ) {
+    public static function getContentText( Content $content = null ) {
+        global $wgContentHandlerTextFallback;
+
         if ( !$content ) return '';
 
         if ( $content instanceof TextContent ) {
-            #XXX: or check by model name?
-            #XXX: or define $content->allowRawData()?
-            #XXX: or define $content->getDefaultWikiText()?
             return $content->getNativeData();
         }
 
-        #XXX: this must not be used for editing, otherwise we may loose data:
-        #XXX:      e.g. if this returns the "main" text from a multipart page, all attachments would be lost
+        if ( $wgContentHandlerTextFallback == 'fail' ) throw new MWException( "Attempt to get text from Content with model " . $content->getModelName() );
+        if ( $wgContentHandlerTextFallback == 'serialize' ) return $content->serialize();
 
         return null;
     }
@@ -167,8 +166,6 @@ abstract class ContentHandler {
 
     public abstract function emptyContent();
 
-    # public abstract function doPreSaveTransform( $title, $obj ); #TODO...
-
     /**
      * Return an Article object suitable for viewing the given object
      *
@@ -210,12 +207,19 @@ abstract class ContentHandler {
     }
 
     /**
-    public function updatePage( $title, $obj ) {
-    }
-    **/
-    
-    public function getDiffEngine( Article $article ) {
-        $de = new DifferenceEngine( $article->getContext() );
+     * Factory
+     * @param $context IContextSource context to use, anything else will be ignored
+     * @param $old Integer old ID we want to show and diff with.
+     * @param $new String either 'prev' or 'next'.
+     * @param $rcid Integer ??? FIXME (default 0)
+     * @param $refreshCache boolean If set, refreshes the diff cache
+     * @param $unhide boolean If set, allow viewing deleted revs
+     */
+    public function getDifferenceEngine( IContextSource $context, $old = 0, $new = 0, $rcid = 0, #FIMXE: use everywhere!
+                                         $refreshCache = false, $unhide = false ) {
+
+        $de = new DifferenceEngine( $context, $old, $new, $rcid, $refreshCache, $unhide );
+
         return $de;
     }
 
@@ -300,88 +304,120 @@ 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 '';
     }
 
+    /**
+     * Get the Content object that needs to be saved in order to undo all revisions
+     * between $undo and $undoafter. Revisions must belong to the same page,
+     * must exist and must not be deleted
+     * @param $undo Revision
+     * @param $undoafter null|Revision Must be an earlier revision than $undo
+     * @return mixed string on success, false on failure
+     */
+    public function getUndoContent( Revision $current, Revision $undo, Revision $undoafter = null ) {
+        $cur_content = $current->getContent();
 
-    #TODO: cover patch/undo just like merge3.
+        if ( empty( $cur_content ) ) {
+            return false; // no page
+        }
+
+        $undo_content = $undo->getContent();
+        $undoafter_content = $undoafter->getContent();
+
+        if ( $cur_content->equals( $undo_content ) ) {
+            # No use doing a merge if it's just a straight revert.
+            return $undoafter_content;
+        }
+
+        $undone_content = $this->merge3( $undo_content, $undoafter_content, $cur_content );
+
+        return $undone_content;
+    }
 
     #TODO: how to handle extra message for JS/CSS previews??
     #TODO: Article::showCssOrJsPage ---> specialized classes!