Completed
Branch master (05c729)
by
unknown
20:00
created

OldLocalFile::loadFromDB()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 21
Code Lines 16

Duplication

Lines 5
Ratio 23.81 %

Importance

Changes 0
Metric Value
cc 4
eloc 16
nc 8
nop 1
dl 5
loc 21
rs 9.0534
c 0
b 0
f 0
1
<?php
2
/**
3
 * Old file in the oldimage table.
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
 * http://www.gnu.org/copyleft/gpl.html
19
 *
20
 * @file
21
 * @ingroup FileAbstraction
22
 */
23
24
/**
25
 * Class to represent a file in the oldimage table
26
 *
27
 * @ingroup FileAbstraction
28
 */
29
class OldLocalFile extends LocalFile {
30
	/** @var string Timestamp */
31
	protected $requestedTime;
32
33
	/** @var string Archive name */
34
	protected $archive_name;
35
36
	const CACHE_VERSION = 1;
37
	const MAX_CACHE_ROWS = 20;
38
39
	/**
40
	 * @param Title $title
41
	 * @param FileRepo $repo
42
	 * @param null|int $time Timestamp or null
43
	 * @return OldLocalFile
44
	 * @throws MWException
45
	 */
46
	static function newFromTitle( $title, $repo, $time = null ) {
47
		# The null default value is only here to avoid an E_STRICT
48
		if ( $time === null ) {
49
			throw new MWException( __METHOD__ . ' got null for $time parameter' );
50
		}
51
52
		return new self( $title, $repo, $time, null );
53
	}
54
55
	/**
56
	 * @param Title $title
57
	 * @param FileRepo $repo
58
	 * @param string $archiveName
59
	 * @return OldLocalFile
60
	 */
61
	static function newFromArchiveName( $title, $repo, $archiveName ) {
62
		return new self( $title, $repo, null, $archiveName );
63
	}
64
65
	/**
66
	 * @param stdClass $row
67
	 * @param FileRepo $repo
68
	 * @return OldLocalFile
69
	 */
70
	static function newFromRow( $row, $repo ) {
71
		$title = Title::makeTitle( NS_FILE, $row->oi_name );
72
		$file = new self( $title, $repo, null, $row->oi_archive_name );
73
		$file->loadFromRow( $row, 'oi_' );
74
75
		return $file;
76
	}
77
78
	/**
79
	 * Create a OldLocalFile from a SHA-1 key
80
	 * Do not call this except from inside a repo class.
81
	 *
82
	 * @param string $sha1 Base-36 SHA-1
83
	 * @param LocalRepo $repo
84
	 * @param string|bool $timestamp MW_timestamp (optional)
85
	 *
86
	 * @return bool|OldLocalFile
87
	 */
88 View Code Duplication
	static function newFromKey( $sha1, $repo, $timestamp = false ) {
89
		$dbr = $repo->getSlaveDB();
90
91
		$conds = [ 'oi_sha1' => $sha1 ];
92
		if ( $timestamp ) {
93
			$conds['oi_timestamp'] = $dbr->timestamp( $timestamp );
94
		}
95
96
		$row = $dbr->selectRow( 'oldimage', self::selectFields(), $conds, __METHOD__ );
97
		if ( $row ) {
98
			return self::newFromRow( $row, $repo );
99
		} else {
100
			return false;
101
		}
102
	}
103
104
	/**
105
	 * Fields in the oldimage table
106
	 * @return array
107
	 */
108
	static function selectFields() {
109
		return [
110
			'oi_name',
111
			'oi_archive_name',
112
			'oi_size',
113
			'oi_width',
114
			'oi_height',
115
			'oi_metadata',
116
			'oi_bits',
117
			'oi_media_type',
118
			'oi_major_mime',
119
			'oi_minor_mime',
120
			'oi_description',
121
			'oi_user',
122
			'oi_user_text',
123
			'oi_timestamp',
124
			'oi_deleted',
125
			'oi_sha1',
126
		];
127
	}
128
129
	/**
130
	 * @param Title $title
131
	 * @param FileRepo $repo
132
	 * @param string $time Timestamp or null to load by archive name
133
	 * @param string $archiveName Archive name or null to load by timestamp
134
	 * @throws MWException
135
	 */
136
	function __construct( $title, $repo, $time, $archiveName ) {
137
		parent::__construct( $title, $repo );
138
		$this->requestedTime = $time;
139
		$this->archive_name = $archiveName;
140
		if ( is_null( $time ) && is_null( $archiveName ) ) {
141
			throw new MWException( __METHOD__ . ': must specify at least one of $time or $archiveName' );
142
		}
143
	}
144
145
	/**
146
	 * @return bool
147
	 */
148
	function getCacheKey() {
149
		return false;
150
	}
151
152
	/**
153
	 * @return string
154
	 */
155
	function getArchiveName() {
156
		if ( !isset( $this->archive_name ) ) {
157
			$this->load();
158
		}
159
160
		return $this->archive_name;
161
	}
162
163
	/**
164
	 * @return bool
165
	 */
166
	function isOld() {
167
		return true;
168
	}
169
170
	/**
171
	 * @return bool
172
	 */
173
	function isVisible() {
174
		return $this->exists() && !$this->isDeleted( File::DELETED_FILE );
175
	}
176
177
	function loadFromDB( $flags = 0 ) {
178
		$this->dataLoaded = true;
179
180
		$dbr = ( $flags & self::READ_LATEST )
181
			? $this->repo->getMasterDB()
0 ignored issues
show
Bug introduced by
The method getMasterDB does only exist in LocalRepo, but not in FileRepo and ForeignAPIRepo.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
182
			: $this->repo->getSlaveDB();
0 ignored issues
show
Bug introduced by
The method getSlaveDB does only exist in LocalRepo, but not in FileRepo and ForeignAPIRepo.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
183
184
		$conds = [ 'oi_name' => $this->getName() ];
185 View Code Duplication
		if ( is_null( $this->requestedTime ) ) {
186
			$conds['oi_archive_name'] = $this->archive_name;
187
		} else {
188
			$conds['oi_timestamp'] = $dbr->timestamp( $this->requestedTime );
189
		}
190
		$row = $dbr->selectRow( 'oldimage', $this->getCacheFields( 'oi_' ),
191
			$conds, __METHOD__, [ 'ORDER BY' => 'oi_timestamp DESC' ] );
192
		if ( $row ) {
193
			$this->loadFromRow( $row, 'oi_' );
194
		} else {
195
			$this->fileExists = false;
196
		}
197
	}
198
199
	/**
200
	 * Load lazy file metadata from the DB
201
	 */
202
	protected function loadExtraFromDB() {
203
		$this->extraDataLoaded = true;
204
		$dbr = $this->repo->getSlaveDB();
0 ignored issues
show
Bug introduced by
The method getSlaveDB does only exist in LocalRepo, but not in FileRepo and ForeignAPIRepo.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
205
		$conds = [ 'oi_name' => $this->getName() ];
206 View Code Duplication
		if ( is_null( $this->requestedTime ) ) {
207
			$conds['oi_archive_name'] = $this->archive_name;
208
		} else {
209
			$conds['oi_timestamp'] = $dbr->timestamp( $this->requestedTime );
210
		}
211
		// In theory the file could have just been renamed/deleted...oh well
212
		$row = $dbr->selectRow( 'oldimage', $this->getLazyCacheFields( 'oi_' ),
213
			$conds, __METHOD__, [ 'ORDER BY' => 'oi_timestamp DESC' ] );
214
215
		if ( !$row ) { // fallback to master
216
			$dbr = $this->repo->getMasterDB();
0 ignored issues
show
Bug introduced by
The method getMasterDB does only exist in LocalRepo, but not in FileRepo and ForeignAPIRepo.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
217
			$row = $dbr->selectRow( 'oldimage', $this->getLazyCacheFields( 'oi_' ),
218
				$conds, __METHOD__, [ 'ORDER BY' => 'oi_timestamp DESC' ] );
219
		}
220
221
		if ( $row ) {
222
			foreach ( $this->unprefixRow( $row, 'oi_' ) as $name => $value ) {
223
				$this->$name = $value;
224
			}
225
		} else {
226
			throw new MWException( "Could not find data for image '{$this->archive_name}'." );
227
		}
228
	}
229
230
	/**
231
	 * @param string $prefix
232
	 * @return array
233
	 */
234
	function getCacheFields( $prefix = 'img_' ) {
235
		$fields = parent::getCacheFields( $prefix );
236
		$fields[] = $prefix . 'archive_name';
237
		$fields[] = $prefix . 'deleted';
238
239
		return $fields;
240
	}
241
242
	/**
243
	 * @return string
244
	 */
245
	function getRel() {
246
		return 'archive/' . $this->getHashPath() . $this->getArchiveName();
247
	}
248
249
	/**
250
	 * @return string
251
	 */
252
	function getUrlRel() {
253
		return 'archive/' . $this->getHashPath() . rawurlencode( $this->getArchiveName() );
254
	}
255
256
	function upgradeRow() {
257
		$this->loadFromFile();
258
259
		# Don't destroy file info of missing files
260
		if ( !$this->fileExists ) {
261
			wfDebug( __METHOD__ . ": file does not exist, aborting\n" );
262
263
			return;
264
		}
265
266
		$dbw = $this->repo->getMasterDB();
0 ignored issues
show
Bug introduced by
The method getMasterDB does only exist in LocalRepo, but not in FileRepo and ForeignAPIRepo.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
267
		list( $major, $minor ) = self::splitMime( $this->mime );
268
269
		wfDebug( __METHOD__ . ': upgrading ' . $this->archive_name . " to the current schema\n" );
270
		$dbw->update( 'oldimage',
271
			[
272
				'oi_size' => $this->size, // sanity
273
				'oi_width' => $this->width,
274
				'oi_height' => $this->height,
275
				'oi_bits' => $this->bits,
276
				'oi_media_type' => $this->media_type,
277
				'oi_major_mime' => $major,
278
				'oi_minor_mime' => $minor,
279
				'oi_metadata' => $this->metadata,
280
				'oi_sha1' => $this->sha1,
281
			], [
282
				'oi_name' => $this->getName(),
283
				'oi_archive_name' => $this->archive_name ],
284
			__METHOD__
285
		);
286
	}
287
288
	/**
289
	 * @param int $field One of DELETED_* bitfield constants for file or
290
	 *   revision rows
291
	 * @return bool
292
	 */
293
	function isDeleted( $field ) {
294
		$this->load();
295
296
		return ( $this->deleted & $field ) == $field;
297
	}
298
299
	/**
300
	 * Returns bitfield value
301
	 * @return int
302
	 */
303
	function getVisibility() {
304
		$this->load();
305
306
		return (int)$this->deleted;
307
	}
308
309
	/**
310
	 * Determine if the current user is allowed to view a particular
311
	 * field of this image file, if it's marked as deleted.
312
	 *
313
	 * @param int $field
314
	 * @param User|null $user User object to check, or null to use $wgUser
315
	 * @return bool
316
	 */
317
	function userCan( $field, User $user = null ) {
318
		$this->load();
319
320
		return Revision::userCanBitfield( $this->deleted, $field, $user );
321
	}
322
323
	/**
324
	 * Upload a file directly into archive. Generally for Special:Import.
325
	 *
326
	 * @param string $srcPath File system path of the source file
327
	 * @param string $archiveName Full archive name of the file, in the form
328
	 *   $timestamp!$filename, where $filename must match $this->getName()
329
	 * @param string $timestamp
330
	 * @param string $comment
331
	 * @param User $user
332
	 * @return Status
333
	 */
334
	function uploadOld( $srcPath, $archiveName, $timestamp, $comment, $user ) {
335
		$this->lock();
336
337
		$dstRel = 'archive/' . $this->getHashPath() . $archiveName;
338
		$status = $this->publishTo( $srcPath, $dstRel );
339
340
		if ( $status->isGood() ) {
341
			if ( !$this->recordOldUpload( $srcPath, $archiveName, $timestamp, $comment, $user ) ) {
342
				$status->fatal( 'filenotfound', $srcPath );
343
			}
344
		}
345
346
		$this->unlock();
347
348
		return $status;
349
	}
350
351
	/**
352
	 * Record a file upload in the oldimage table, without adding log entries.
353
	 *
354
	 * @param string $srcPath File system path to the source file
355
	 * @param string $archiveName The archive name of the file
356
	 * @param string $timestamp
357
	 * @param string $comment Upload comment
358
	 * @param User $user User who did this upload
359
	 * @return bool
360
	 */
361
	protected function recordOldUpload( $srcPath, $archiveName, $timestamp, $comment, $user ) {
362
		$dbw = $this->repo->getMasterDB();
0 ignored issues
show
Bug introduced by
The method getMasterDB does only exist in LocalRepo, but not in FileRepo and ForeignAPIRepo.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
363
364
		$dstPath = $this->repo->getZonePath( 'public' ) . '/' . $this->getRel();
365
		$props = $this->repo->getFileProps( $dstPath );
366
		if ( !$props['fileExists'] ) {
367
			return false;
368
		}
369
370
		$dbw->insert( 'oldimage',
371
			[
372
				'oi_name' => $this->getName(),
373
				'oi_archive_name' => $archiveName,
374
				'oi_size' => $props['size'],
375
				'oi_width' => intval( $props['width'] ),
376
				'oi_height' => intval( $props['height'] ),
377
				'oi_bits' => $props['bits'],
378
				'oi_timestamp' => $dbw->timestamp( $timestamp ),
379
				'oi_description' => $comment,
380
				'oi_user' => $user->getId(),
381
				'oi_user_text' => $user->getName(),
382
				'oi_metadata' => $props['metadata'],
383
				'oi_media_type' => $props['media_type'],
384
				'oi_major_mime' => $props['major_mime'],
385
				'oi_minor_mime' => $props['minor_mime'],
386
				'oi_sha1' => $props['sha1'],
387
			], __METHOD__
388
		);
389
390
		return true;
391
	}
392
393
	/**
394
	 * If archive name is an empty string, then file does not "exist"
395
	 *
396
	 * This is the case for a couple files on Wikimedia servers where
397
	 * the old version is "lost".
398
	 */
399
	public function exists() {
400
		$archiveName = $this->getArchiveName();
401
		if ( $archiveName === '' || !is_string( $archiveName ) ) {
402
			return false;
403
		}
404
		return parent::exists();
405
	}
406
}
407