Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 80
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialSwitchCargoTable
0.00% covered (danger)
0.00%
0 / 80
0.00% covered (danger)
0.00%
0 / 4
182
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
 doesWrites
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 switchInTableReplacement
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
42
 execute
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2/**
3 * An interface to delete a "Cargo table", which can be one or more real
4 * database tables.
5 *
6 * @author Yaron Koren
7 * @ingroup Cargo
8 */
9
10use MediaWiki\MediaWikiServices;
11
12class SpecialSwitchCargoTable extends UnlistedSpecialPage {
13
14    public function __construct() {
15        parent::__construct( 'SwitchCargoTable', 'recreatecargodata' );
16    }
17
18    public function doesWrites() {
19        return true;
20    }
21
22    /**
23     * The table being switched here is a Cargo table, not a DB table per
24     * se - a Cargo table corresponds to a main DB table, plus
25     * potentially one or more helper tables; all need to be switched.
26     * Also, records need to be removed, and modified, in the cargo_tables and
27     * cargo_pages tables.
28     */
29    public static function switchInTableReplacement(
30        $mainTable,
31        $fieldTables,
32        $fieldHelperTables,
33        User $user
34    ) {
35        $cdb = CargoUtils::getDB();
36        try {
37            $cdb->begin();
38
39            // The helper tables' names come from the database,
40            // so they already contain '__NEXT' - remove that,
41            // instead of adding it, when getting table names.
42            foreach ( $fieldTables as $fieldTable ) {
43                $origFieldTable = str_replace( '__NEXT', '', $fieldTable );
44                $cdb->dropTable( $origFieldTable );
45                $cdb->query( 'ALTER TABLE ' .
46                    $cdb->tableName( $fieldTable ) .
47                    ' RENAME TO ' .
48                    $cdb->tableName( $origFieldTable ) );
49            }
50            if ( is_array( $fieldHelperTables ) ) {
51                foreach ( $fieldHelperTables as $fieldHelperTable ) {
52                    $origFieldHelperTable = str_replace( '__NEXT', '', $fieldHelperTable );
53                    $cdb->dropTable( $origFieldHelperTable );
54                    $cdb->query( 'ALTER TABLE ' .
55                        $cdb->tableName( $fieldHelperTable ) .
56                        ' RENAME TO ' .
57                        $cdb->tableName( $origFieldHelperTable ) );
58                }
59            }
60
61            $cdb->dropTable( $mainTable );
62            $cdb->query( 'ALTER TABLE ' .
63                $cdb->tableName( $mainTable . '__NEXT' ) .
64                ' RENAME TO ' . $cdb->tableName( $mainTable ) );
65
66            $cdb->commit();
67        } catch ( Exception $e ) {
68            throw new MWException( "Caught exception ($e) while trying to switch in replacement for Cargo table. "
69            . "Please make sure that your database user account has the DROP permission." );
70        }
71
72        $dbw = wfGetDB( DB_MASTER );
73        $dbw->delete( 'cargo_tables', [ 'main_table' => $mainTable ] );
74        $dbw->delete( 'cargo_pages', [ 'table_name' => $mainTable ] );
75        $dbw->update( 'cargo_tables', [ 'main_table' => $mainTable ], [ 'main_table' => $mainTable . '__NEXT' ] );
76        $origFieldTableNames = [];
77        foreach ( $fieldTables as $fieldTable ) {
78            $origFieldTableNames[] = str_replace( '__NEXT', '', $fieldTable );
79        }
80        $dbw->update( 'cargo_tables', [ 'field_tables' => serialize( $origFieldTableNames ) ], [ 'main_table' => $mainTable ] );
81        $dbw->update( 'cargo_pages', [ 'table_name' => $mainTable ], [ 'table_name' => $mainTable . '__NEXT' ] );
82
83        CargoUtils::logTableAction( 'replacetable', $mainTable, $user );
84    }
85
86    public function execute( $subpage = false ) {
87        $this->checkPermissions();
88
89        $out = $this->getOutput();
90        $tableName = $subpage;
91        $out->enableOOUI();
92
93        $this->setHeaders();
94        if ( $tableName == '' ) {
95            CargoUtils::displayErrorMessage( $out, $this->msg( "cargo-notable" ) );
96            return true;
97        }
98
99        // Make sure that this table, and its replacement, both exist.
100        $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
101        $dbr = $lb->getConnectionRef( DB_REPLICA );
102        $res = $dbr->select( 'cargo_tables', [ 'main_table', 'field_tables', 'field_helper_tables' ],
103            [ 'main_table' => $tableName ] );
104        if ( $res->numRows() == 0 ) {
105            CargoUtils::displayErrorMessage( $out, $this->msg( "cargo-unknowntable", $tableName ) );
106            return true;
107        }
108        $res = $dbr->select( 'cargo_tables', [ 'main_table', 'field_tables', 'field_helper_tables' ],
109            [ 'main_table' => $tableName . '__NEXT' ] );
110        if ( $res->numRows() == 0 ) {
111            CargoUtils::displayErrorMessage( $out, $this->msg( "cargo-unknowntable", $tableName . "__NEXT" ) );
112            return true;
113        }
114
115        $ctPage = CargoUtils::getSpecialPage( 'CargoTables' );
116        $row = $res->fetchRow();
117        $fieldTables = unserialize( $row['field_tables'] );
118        $fieldHelperTables = unserialize( $row['field_helper_tables'] );
119
120        if ( $this->getRequest()->getCheck( 'switch' ) ) {
121            self::switchInTableReplacement( $tableName, $fieldTables, $fieldHelperTables, $this->getUser() );
122            $text = Html::element( 'p', null, $this->msg( 'cargo-switchtables-success', $tableName )->parse() ) . "\n";
123            $tablesLink = CargoUtils::makeLink( $this->getLinkRenderer(),
124                $ctPage->getPageTitle(), $ctPage->getDescription() );
125            $text .= Html::rawElement( 'p', null, $this->msg( 'returnto', $tablesLink )->text() );
126            $out->addHTML( $text );
127            return true;
128        }
129
130        $ctURL = $ctPage->getPageTitle()->getLocalURL();
131        $tableLink = Html::element( 'a', [ 'href' => "$ctURL/$tableName", ], $tableName );
132
133        $text = Html::rawElement( 'p', null, $this->msg( 'cargo-switchtables-confirm', $tableLink )->text() );
134        $out->addHTML( $text );
135
136        $htmlForm = HTMLForm::factory( 'ooui', [], $this->getContext() );
137        $htmlForm
138            ->setSubmitName( 'switch' )
139            ->setSubmitTextMsg( 'cargo-switchtables-switch' )
140            ->prepareForm()
141            ->displayForm( false );
142
143        return true;
144    }
145
146}