Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
28.07% covered (danger)
28.07%
16 / 57
33.33% covered (danger)
33.33%
2 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
LinksMigration
28.07% covered (danger)
28.07%
16 / 57
33.33% covered (danger)
33.33%
2 / 6
124.55
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getLinksConditions
58.33% covered (warning)
58.33%
7 / 12
0.00% covered (danger)
0.00%
0 / 1
3.65
 getQueryInfo
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
12
 getTitleFields
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 isMigrationReadNew
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 assertMapping
45.45% covered (danger)
45.45%
5 / 11
0.00% covered (danger)
0.00%
0 / 1
11.84
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21namespace MediaWiki\Linker;
22
23use InvalidArgumentException;
24use MediaWiki\Config\Config;
25use MediaWiki\MainConfigNames;
26
27/**
28 * Service for compat reading of links tables
29 *
30 * @since 1.39
31 */
32class LinksMigration {
33
34    /** @var Config */
35    private $config;
36
37    /** @var LinkTargetLookup */
38    private $linkTargetLookup;
39
40    /** @var array[] */
41    public static $mapping = [
42        'templatelinks' => [
43            'config' => -1,
44            'page_id' => 'tl_from',
45            // Used by the updater only
46            'ns' => 'tl_namespace',
47            // Used by the updater only
48            'title' => 'tl_title',
49            'target_id' => 'tl_target_id',
50            'deprecated_configs' => [],
51        ],
52        'pagelinks' => [
53            'config' => MainConfigNames::PageLinksSchemaMigrationStage,
54            'page_id' => 'pl_from',
55            'ns' => 'pl_namespace',
56            'title' => 'pl_title',
57            'target_id' => 'pl_target_id',
58            'deprecated_configs' => [
59                SCHEMA_COMPAT_WRITE_OLD,
60                SCHEMA_COMPAT_READ_OLD
61            ],
62        ],
63        'categorylinks' => [
64            'config' => MainConfigNames::CategoryLinksSchemaMigrationStage,
65            'page_id' => 'cl_from',
66            'ns' => 14,
67            'title' => 'cl_to',
68            'target_id' => 'cl_target_id',
69            'deprecated_configs' => [],
70        ],
71    ];
72
73    /** @var string[] */
74    public static $prefixToTableMapping = [
75        'tl' => 'templatelinks',
76        'pl' => 'pagelinks',
77        'cl' => 'categorylinks',
78    ];
79
80    public function __construct( Config $config, LinkTargetLookup $linktargetLookup ) {
81        $this->config = $config;
82        $this->linkTargetLookup = $linktargetLookup;
83    }
84
85    /**
86     * Return the conditions to be used in querying backlinks to a page
87     *
88     * @param string $table
89     * @param LinkTarget $linkTarget
90     * @return array
91     */
92    public function getLinksConditions( string $table, LinkTarget $linkTarget ): array {
93        $this->assertMapping( $table );
94        if ( $this->isMigrationReadNew( $table ) ) {
95            $targetId = $this->linkTargetLookup->getLinkTargetId( $linkTarget );
96            // Not found, it shouldn't pick anything
97            if ( !$targetId ) {
98                return [ '1=0' ];
99            }
100            return [
101                self::$mapping[$table]['target_id'] => $targetId,
102            ];
103        } else {
104            return [
105                self::$mapping[$table]['ns'] => $linkTarget->getNamespace(),
106                self::$mapping[$table]['title'] => $linkTarget->getDBkey(),
107            ];
108        }
109    }
110
111    /**
112     * Return the query to be used when you want to or from a group of pages
113     *
114     * @param string $table
115     * @param string $joinTable table to end the join chain. Most of the time it's linktarget
116     * @param string $joinType
117     * @return array
118     */
119    public function getQueryInfo( string $table, string $joinTable = 'linktarget', string $joinType = 'JOIN' ) {
120        $this->assertMapping( $table );
121        if ( $this->isMigrationReadNew( $table ) ) {
122            $targetId = self::$mapping[$table]['target_id'];
123            if ( $joinTable === 'linktarget' ) {
124                $tables = [ $table, 'linktarget' ];
125            } else {
126                $tables = [ 'linktarget', $table ];
127            }
128            return [
129                'tables' => $tables,
130                'fields' => [
131                    $targetId,
132                    'lt_namespace',
133                    'lt_title'
134                ],
135                'joins' => [ $joinTable => [
136                    $joinType,
137                    [ "$targetId=lt_id" ]
138                ] ],
139            ];
140        } else {
141            return [
142                'fields' => [
143                    self::$mapping[$table]['ns'],
144                    self::$mapping[$table]['title']
145                ],
146                'tables' => [ $table ],
147                'joins' => [],
148            ];
149        }
150    }
151
152    public function getTitleFields( $table ) {
153        $this->assertMapping( $table );
154
155        if ( $this->isMigrationReadNew( $table ) ) {
156            return [ 'lt_namespace', 'lt_title' ];
157        } else {
158            return [ self::$mapping[$table]['ns'], self::$mapping[$table]['title'] ];
159        }
160    }
161
162    private function isMigrationReadNew( string $table ): bool {
163        return self::$mapping[$table]['config'] === -1 ||
164            $this->config->get( self::$mapping[$table]['config'] ) & SCHEMA_COMPAT_READ_NEW;
165    }
166
167    private function assertMapping( string $table ) {
168        if ( !isset( self::$mapping[$table] ) ) {
169            throw new InvalidArgumentException(
170                "LinksMigration doesn't support the $table table yet"
171            );
172        }
173
174        if ( self::$mapping[$table]['config'] !== -1 && self::$mapping[$table]['deprecated_configs'] ) {
175            $config = $this->config->get( self::$mapping[$table]['config'] );
176            foreach ( self::$mapping[$table]['deprecated_configs'] as $deprecatedConfig ) {
177                if ( $config & $deprecatedConfig ) {
178                    throw new InvalidArgumentException(
179                        "LinksMigration config $config on $table table is not supported anymore"
180                    );
181                }
182            }
183
184        }
185    }
186}