Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
57.41% covered (warning)
57.41%
31 / 54
20.00% covered (danger)
20.00%
1 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
PageArchive
58.49% covered (warning)
58.49%
31 / 53
20.00% covered (danger)
20.00%
1 / 5
17.15
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 listPagesBySearch
50.00% covered (danger)
50.00%
13 / 26
0.00% covered (danger)
0.00%
0 / 1
6.00
 listPagesByPrefix
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
2.00
 listPages
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 listFiles
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * @license GPL-2.0-or-later
4 * @file
5 */
6
7namespace MediaWiki\Page;
8
9use MediaWiki\FileRepo\File\FileSelectQueryBuilder;
10use MediaWiki\MediaWikiServices;
11use MediaWiki\Title\Title;
12use Wikimedia\Rdbms\IExpression;
13use Wikimedia\Rdbms\IReadableDatabase;
14use Wikimedia\Rdbms\IResultWrapper;
15use Wikimedia\Rdbms\LikeValue;
16use Wikimedia\Rdbms\SelectQueryBuilder;
17
18/**
19 * Used to show archived pages and eventually restore them.
20 */
21class PageArchive {
22
23    protected Title $title;
24
25    public function __construct( Title $title ) {
26        $this->title = $title;
27    }
28
29    /**
30     * List deleted pages recorded in the archive matching the
31     * given term, using search engine archive.
32     * Returns result wrapper with (ar_namespace, ar_title, count) fields.
33     *
34     * @param string $term Search term
35     * @return IResultWrapper|bool
36     */
37    public static function listPagesBySearch( $term ) {
38        $title = Title::newFromText( $term );
39        if ( $title ) {
40            $ns = $title->getNamespace();
41            $termMain = $title->getText();
42            $termDb = $title->getDBkey();
43        } else {
44            // Prolly won't work too good
45            // @todo handle bare namespace names cleanly?
46            $ns = 0;
47            $termMain = $termDb = $term;
48        }
49
50        // Try search engine first
51        $engine = MediaWikiServices::getInstance()->newSearchEngine();
52        $engine->setLimitOffset( 100 );
53        $engine->setNamespaces( [ $ns ] );
54        $results = $engine->searchArchiveTitle( $termMain );
55        if ( !$results->isOK() ) {
56            $results = [];
57        } else {
58            $results = $results->getValue();
59        }
60
61        if ( !$results ) {
62            // Fall back to regular prefix search
63            return self::listPagesByPrefix( $term );
64        }
65
66        $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
67        $condTitles = array_values( array_unique( array_map( static function ( Title $t ) {
68            return $t->getDBkey();
69        }, $results ) ) );
70        $conds = [
71            'ar_namespace' => $ns,
72            $dbr->expr( 'ar_title', '=', $condTitles )
73                ->or( 'ar_title', IExpression::LIKE, new LikeValue( $termDb, $dbr->anyString() ) ),
74        ];
75
76        return self::listPages( $dbr, $conds );
77    }
78
79    /**
80     * List deleted pages recorded in the archive table matching the
81     * given title prefix.
82     * Returns result wrapper with (ar_namespace, ar_title, count) fields.
83     *
84     * @param string $prefix Title prefix
85     * @return IResultWrapper|bool
86     */
87    public static function listPagesByPrefix( $prefix ) {
88        $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
89
90        $title = Title::newFromText( $prefix );
91        if ( $title ) {
92            $ns = $title->getNamespace();
93            $prefix = $title->getDBkey();
94        } else {
95            // Prolly won't work too good
96            // @todo handle bare namespace names cleanly?
97            $ns = 0;
98        }
99
100        $conds = [
101            'ar_namespace' => $ns,
102            $dbr->expr( 'ar_title', IExpression::LIKE, new LikeValue( $prefix, $dbr->anyString() ) ),
103        ];
104
105        return self::listPages( $dbr, $conds );
106    }
107
108    /**
109     * @param IReadableDatabase $dbr
110     * @param string|array $condition
111     * @return IResultWrapper
112     */
113    protected static function listPages( IReadableDatabase $dbr, $condition ) {
114        return $dbr->newSelectQueryBuilder()
115            ->select( [ 'ar_namespace', 'ar_title', 'count' => 'COUNT(*)' ] )
116            ->from( 'archive' )
117            ->where( $condition )
118            ->groupBy( [ 'ar_namespace', 'ar_title' ] )
119            ->orderBy( [ 'ar_namespace', 'ar_title' ] )
120            ->limit( 100 )
121            ->caller( __METHOD__ )->fetchResultSet();
122    }
123
124    /**
125     * List the deleted file revisions for this page, if it's a file page.
126     * Returns a result wrapper with various filearchive fields, or null
127     * if not a file page.
128     *
129     * @return IResultWrapper|null
130     * @todo Does this belong in Image for fuller encapsulation?
131     */
132    public function listFiles() {
133        if ( $this->title->getNamespace() !== NS_FILE ) {
134            return null;
135        }
136
137        $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
138        $queryBuilder = FileSelectQueryBuilder::newForArchivedFile( $dbr );
139        $queryBuilder->where( [ 'fa_name' => $this->title->getDBkey() ] )
140            ->orderBy( 'fa_timestamp', SelectQueryBuilder::SORT_DESC );
141        return $queryBuilder->caller( __METHOD__ )->fetchResultSet();
142    }
143
144}
145
146/** @deprecated class alias since 1.44 */
147class_alias( PageArchive::class, 'PageArchive' );