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    public static $mapping = [
41        'templatelinks' => [
42            'config' => -1,
43            'page_id' => 'tl_from',
44            // Used by the updater only
45            'ns' => 'tl_namespace',
46            // Used by the updater only
47            'title' => 'tl_title',
48            'target_id' => 'tl_target_id',
49            'deprecated_configs' => [],
50        ],
51        'pagelinks' => [
52            'config' => MainConfigNames::PageLinksSchemaMigrationStage,
53            'page_id' => 'pl_from',
54            'ns' => 'pl_namespace',
55            'title' => 'pl_title',
56            'target_id' => 'pl_target_id',
57            'deprecated_configs' => [
58                SCHEMA_COMPAT_WRITE_OLD,
59                SCHEMA_COMPAT_READ_OLD
60            ],
61        ],
62    ];
63
64    public static $prefixToTableMapping = [
65        'tl' => 'templatelinks',
66        'pl' => 'pagelinks',
67    ];
68
69    /**
70     * @param Config $config
71     * @param LinkTargetLookup $linktargetLookup
72     */
73    public function __construct( Config $config, LinkTargetLookup $linktargetLookup ) {
74        $this->config = $config;
75        $this->linkTargetLookup = $linktargetLookup;
76    }
77
78    /**
79     * Return the conditions to be used in querying backlinks to a page
80     *
81     * @param string $table
82     * @param LinkTarget $linkTarget
83     * @return array
84     */
85    public function getLinksConditions( string $table, LinkTarget $linkTarget ): array {
86        $this->assertMapping( $table );
87        if ( $this->isMigrationReadNew( $table ) ) {
88            $targetId = $this->linkTargetLookup->getLinkTargetId( $linkTarget );
89            // Not found, it shouldn't pick anything
90            if ( !$targetId ) {
91                return [ '1=0' ];
92            }
93            return [
94                self::$mapping[$table]['target_id'] => $targetId,
95            ];
96        } else {
97            return [
98                self::$mapping[$table]['ns'] => $linkTarget->getNamespace(),
99                self::$mapping[$table]['title'] => $linkTarget->getDBkey(),
100            ];
101        }
102    }
103
104    /**
105     * Return the query to be used when you want to or from a group of pages
106     *
107     * @param string $table
108     * @param string $joinTable table to end the join chain. Most of the time it's linktarget
109     * @param string $joinType
110     * @return array
111     */
112    public function getQueryInfo( string $table, string $joinTable = 'linktarget', string $joinType = 'JOIN' ) {
113        $this->assertMapping( $table );
114        if ( $this->isMigrationReadNew( $table ) ) {
115            $targetId = self::$mapping[$table]['target_id'];
116            if ( $joinTable === 'linktarget' ) {
117                $tables = [ $table, 'linktarget' ];
118            } else {
119                $tables = [ 'linktarget', $table ];
120            }
121            return [
122                'tables' => $tables,
123                'fields' => [
124                    $targetId,
125                    'lt_namespace',
126                    'lt_title'
127                ],
128                'joins' => [ $joinTable => [
129                    $joinType,
130                    [ "$targetId=lt_id" ]
131                ] ],
132            ];
133        } else {
134            return [
135                'fields' => [
136                    self::$mapping[$table]['ns'],
137                    self::$mapping[$table]['title']
138                ],
139                'tables' => [ $table ],
140                'joins' => [],
141            ];
142        }
143    }
144
145    public function getTitleFields( $table ) {
146        $this->assertMapping( $table );
147
148        if ( $this->isMigrationReadNew( $table ) ) {
149            return [ 'lt_namespace', 'lt_title' ];
150        } else {
151            return [ self::$mapping[$table]['ns'], self::$mapping[$table]['title'] ];
152        }
153    }
154
155    private function isMigrationReadNew( string $table ): bool {
156        return self::$mapping[$table]['config'] === -1 ||
157            $this->config->get( self::$mapping[$table]['config'] ) & SCHEMA_COMPAT_READ_NEW;
158    }
159
160    private function assertMapping( string $table ) {
161        if ( !isset( self::$mapping[$table] ) ) {
162            throw new InvalidArgumentException(
163                "LinksMigration doesn't support the $table table yet"
164            );
165        }
166
167        if ( self::$mapping[$table]['config'] !== -1 && self::$mapping[$table]['deprecated_configs'] ) {
168            $config = $this->config->get( self::$mapping[$table]['config'] );
169            foreach ( self::$mapping[$table]['deprecated_configs'] as $deprecatedConfig ) {
170                if ( $config & $deprecatedConfig ) {
171                    throw new InvalidArgumentException(
172                        "LinksMigration config $config on $table table is not supported anymore"
173                    );
174                }
175            }
176
177        }
178    }
179}