* Introduced image "broken links" allowing the user to quickly upload an image with that name
* "Upload a new version of this image" link from the image description page
$this->mTitle->getInternalURL(),
$this->mTitle->getInternalURL( 'history' )
);
- foreach ( $linksTo as $linkTo ) {
- $urls[] = $linkTo->getInternalURL();
- }
- $u = new SquidUpdate( $urls );
+ $u = SquidUpdate::newFromTitles( $linksTo, $urls );
array_push( $wgPostCommitUpdateList, $u );
}
*/
function recordUpload( $oldver, $desc, $copyStatus = '', $source = '' ) {
global $wgUser, $wgLang, $wgTitle, $wgOut, $wgDeferredUpdateList;
- global $wgUseCopyrightUpload;
+ global $wgUseCopyrightUpload, $wgUseSquid, $wgPostCommitUpdateList;
$fname = 'Image::recordUpload';
$dbw =& wfGetDB( DB_MASTER );
wfDebugDieBacktrace( 'Database schema not up to date, please run maintenance/archives/patch-image_name_unique.sql' );
}
- // Delete thumbnails and refresh the cache
+ // Delete thumbnails and refresh the metadata cache
$this->purgeCache();
// Fail now if the image isn't there
$textdesc = $desc;
}
- $now = wfTimestampNow();
+ $now = $dbw->timestamp();
# Test to see if the row exists using INSERT IGNORE
# This avoids race conditions by locking the row until the commit, and also
'img_height' => $this->height,
'img_bits' => $this->bits,
'img_type' => $this->type,
- 'img_timestamp' => $dbw->timestamp($now),
+ 'img_timestamp' => $now,
'img_description' => $desc,
'img_user' => $wgUser->getID(),
'img_user_text' => $wgUser->getName(),
), $fname, 'IGNORE'
);
$descTitle = $this->getTitle();
+ $purgeURLs = array();
if ( $dbw->affectedRows() ) {
# Successfully inserted, this is a new image
'img_height' => $this->height,
'img_bits' => $this->bits,
'img_type' => $this->type,
- 'img_timestamp' => $dbw->timestamp(),
+ 'img_timestamp' => $now,
'img_user' => $wgUser->getID(),
'img_user_text' => $wgUser->getName(),
'img_description' => $desc,
# Invalidate the cache for the description page
$descTitle->invalidateCache();
+ $purgeURLs[] = $descTitle->getInternalURL();
}
+ # Invalidate cache for all pages using this image
+ $linksTo = $this->getLinksTo();
+
+ if ( $wgUseSquid ) {
+ $u = SquidUpdate::newFromTitles( $linksTo, $purgeURLs );
+ array_push( $wgPostCommitUpdateList, $u );
+ }
+ Title::touchArray( $linksTo );
+
$log = new LogPage( 'upload' );
$log->addEntry( 'upload', $descTitle, $desc );
return true;
}
-
+
+ /**
+ * Get an array of Title objects which are articles which use this image
+ * Also adds their IDs to the link cache
+ *
+ * This is mostly copied from Title::getLinksTo()
+ */
+ function getLinksTo( $options = '' ) {
+ global $wgLinkCache;
+ $fname = 'Image::getLinksTo';
+ wfProfileIn( $fname );
+
+ if ( $options ) {
+ $db =& wfGetDB( DB_MASTER );
+ } else {
+ $db =& wfGetDB( DB_SLAVE );
+ }
+
+ extract( $db->tableNames( 'page', 'imagelinks' ) );
+ $encName = $db->addQuotes( $this->name );
+ $sql = "SELECT page_namespace,page_title,page_id FROM $page,$imagelinks WHERE page_id=il_from AND il_to=$encName $options";
+ $res = $db->query( $sql, $fname );
+
+ $retVal = array();
+ if ( $db->numRows( $res ) ) {
+ while ( $row = $db->fetchObject( $res ) ) {
+ if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) {
+ $wgLinkCache->addGoodLink( $row->page_id, $titleObj->getPrefixedDBkey() );
+ $retVal[] = $titleObj;
+ }
+ }
+ }
+ $db->freeResult( $res );
+ return $retVal;
+ }
+
} //class
*/
class ImagePage extends Article {
- /* private */ var $img; // Image object this page is shown for. Initialized in openShowImage, not
- // available in doDelete etc.
-
+ /* private */ var $img; // Image object this page is shown for
+
function view() {
- global $wgUseExternalEditor;
- if( $this->mTitle->getNamespace() == NS_IMAGE ) {
- $this->openShowImage();
- }
+ global $wgUseExternalEditor, $wgOut;
- Article::view();
- if($wgUseExternalEditor) {
- $this->externalEditorLink();
- }
-
- # If the article we've just shown is in the "Image" namespace,
- # follow it with the history list and link list for the image
- # it describes.
+ $this->img = new Image( $this->mTitle );
- if( $this->mTitle->getNamespace() == NS_IMAGE ) {
+ if( $this->mTitle->getNamespace() == NS_IMAGE ) {
+ $this->openShowImage();
+
+ # No need to display noarticletext, we use our own message, output in openShowImage()
+ if ( $this->getID() ) {
+ Article::view();
+ } else {
+ # Just need to set the right headers
+ $wgOut->setArticleFlag( true );
+ $wgOut->setRobotpolicy( 'index,follow' );
+ $wgOut->setPageTitle( $this->mTitle->getPrefixedText() );
+ $wgOut->addMetaTags();
+ $this->viewUpdates();
+ }
+
+ if ( $this->img->exists() ) {
+ $this->uploadNewVersionLink();
+ if ( $wgUseExternalEditor && $this->img->exists() ) {
+ $this->externalEditorLink();
+ }
+ }
$this->closeShowImage();
$this->imageHistory();
$this->imageLinks();
+ } else {
+ Article::view();
}
}
{
global $wgOut, $wgUser, $wgImageLimits, $wgRequest,
$wgUseImageResize, $wgRepositoryBaseUrl,
- $wgUseExternalEditor;
- $this->img = new Image( $this->mTitle );
+ $wgUseExternalEditor, $wgServer;
$full_url = $this->img->getViewURL();
$anchoropen = '';
$anchorclose = '';
$max = $wgImageLimits[$sizeSel];
$maxWidth = $max[0];
$maxHeight = $max[1];
-
+ $sk = $wgUser->getSkin();
if ( $this->img->exists() ) {
-
- $sk = $wgUser->getSkin();
-
if ( $this->img->getType() != '' ) {
# image
$width = $this->img->getWidth();
$wgOut->addWikiText($sharedtext);
}
+ } else {
+ # Image does not exist
+ $wgOut->addWikiText( wfMsg( 'noimage', $this->getUploadUrl() ) );
}
}
+ function getUploadUrl() {
+ global $wgServer;
+ $uploadTitle = Title::makeTitle( NS_SPECIAL, 'Upload' );
+ return $wgServer . $uploadTitle->getLocalUrl( 'wpDestFile=' . urlencode( $this->img->getName() ) );
+ }
+
+
+ function uploadNewVersionLink() {
+ global $wgOut;
+ $wgOut->addWikiText( wfMsg( 'uploadnewversion', $this->getUploadUrl() ) );
+ }
+
function externalEditorLink()
{
global $wgUser,$wgOut;
return;
}
+ $this->img = new Image( $this->mTitle );
+
# Deleting old images doesn't require confirmation
if ( !is_null( $oldimage ) || $confirm ) {
if( $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ), $oldimage ) ) {
function doDelete()
{
global $wgOut, $wgUser, $wgContLang, $wgRequest;
- global $wgUseSquid, $wgInternalServer, $wgDeferredUpdateList;
+ global $wgUseSquid, $wgInternalServer, $wgPostCommitUpdateList;
$fname = 'ImagePage::doDelete';
$reason = $wgRequest->getVal( 'wpReason' );
$dbw->delete( 'image', array( 'img_name' => $image ) );
$res = $dbw->select( 'oldimage', array( 'oi_archive_name' ), array( 'oi_name' => $image ) );
+ # Purge archive URLs from the squid
$urlArr = Array();
while ( $s = $dbw->fetchObject( $res ) ) {
$this->doDeleteOldImage( $s->oi_archive_name );
$urlArr[] = $wgInternalServer.wfImageArchiveUrl( $s->oi_archive_name );
}
-
- # Defer purging of archived URLs
+
+ # And also the HTML of all pages using this image
+ $linksTo = $this->img->getLinksTo();
if ( $wgUseSquid ) {
- /* this needs to be done after LinksUpdate */
- $u = new SquidUpdate( $urlArr );
- array_push( $wgDeferredUpdateList, $u );
+ $u = SquidUpdate::newFromTitles( $linksTo, $urlArr );
+ array_push( $wgPostCommitUpdateList, $u );
}
$dbw->delete( 'oldimage', array( 'oi_name' => $image ) );
$article = new Article( $this->mTitle );
$article->doDeleteArticle( $reason ); # ignore errors
+ # Invalidate parser cache and client cache for pages using this image
+ # This is left until relatively late to reduce lock time
+ Title::touchArray( $linksTo );
+
/* Delete thumbnails and refresh image metadata cache */
- $imgObj = new Image( $this->mTitle );
- $imgObj->purgeCache();
+ $this->img->purgeCache();
+
$deleted = $image;
}
$u = $nt->escapeLocalURL();
if ( $url == '' ) {
- $s = wfMsg( 'missingimage', $img->getName() );
- $s .= "<br />{$alt}<br />{$url}<br />\n";
+ $s = $this->makeBrokenImageLinkObj( $img->getTitle() );
+ //$s .= "<br />{$alt}<br />{$url}<br />\n";
} else {
$s = '<a href="'.$u.'" class="image" title="'.$alt.'">' .
'<img src="'.$url.'" alt="'.$alt.'" longdesc="'.$u.'" /></a>';
$s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">";
if ( $thumbUrl == '' ) {
- $s .= wfMsg( 'missingimage', $img->getName() );
+ $s .= $this->makeBrokenImageLinkObj( $img->getTitle );
$zoomicon = '';
} else {
$s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
$s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div></div>";
return str_replace("\n", ' ', $s);
}
+
+ /**
+ * Pass a title object, not a title string
+ */
+ function makeBrokenImageLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
+ # Fail gracefully
+ if ( ! isset($nt) ) {
+ # wfDebugDieBacktrace();
+ return "<!-- ERROR -->{$prefix}{$text}{$trail}";
+ }
+
+ $fname = 'Skin::makeBrokenImageLinkObj';
+ wfProfileIn( $fname );
+
+ $q = 'wpDestFile=' . urlencode( $nt->getDBkey() );
+ if ( '' != $query ) {
+ $q .= "&$query";
+ }
+ $uploadTitle = Title::makeTitle( NS_SPECIAL, 'Upload' );
+ $url = $uploadTitle->escapeLocalURL( $q );
+
+ if ( '' == $text ) {
+ $text = htmlspecialchars( $nt->getPrefixedText() );
+ }
+ $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
+ $inside = '';
+ if ( '' != $trail ) {
+ if ( preg_match( $this->linktrail, $trail, $m ) ) {
+ $inside = $m[1];
+ $trail = $m[2];
+ }
+ }
+ $s = "<a href=\"{$url}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
+
+ wfProfileOut( $fname );
+ return $s;
+ }
+
/** @todo document */
function makeMediaLink( $name, $url, $alt = '' ) {
$nt = Title::makeTitleSafe( NS_IMAGE, $name );
return new SquidUpdate( $blurlArr );
}
+ /* static */ function newFromTitles( &$titles, $urlArr = array() ) {
+ foreach ( $titles as $title ) {
+ $urlArr[] = $title->getInternalURL();
+ }
+ return new SquidUpdate( $urlArr );
+ }
+
/* static */ function newSimplePurge( &$title ) {
$urlArr = $title->getSquidURLs();
return new SquidUpdate( $blurlArr );
'nolinkstoimage' => 'There are no pages that link to this image.',
'sharedupload' => 'This file is a shared upload and may be used by other projects.',
'shareduploadwiki' => 'Please see the [$1 image description page] for further information.',
+'noimage' => "No image by this name exists.
+
+<div class=\"editExternally\">
+'''[$1 Upload this image]'''
+</div><br clear=all />",
+'uploadnewversion' => "<div class=\"editExternally\">
+[$1 Upload a new version of this image]
+</div><br clear=all />",
# Statistics
#