Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 88
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 / 88
0.00% covered (danger)
0.00%
0 / 4
156
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 / 43
0.00% covered (danger)
0.00%
0 / 1
30
 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        $origFieldTableNames = [];
37        $origFieldHelperTableNames = [];
38        try {
39            $cdb->begin();
40
41            // The helper tables' names come from the database,
42            // so they already contain '__NEXT' - remove that,
43            // instead of adding it, when getting table names.
44            foreach ( $fieldTables as $fieldTable ) {
45                $origFieldTable = str_replace( '__NEXT', '', $fieldTable );
46                $origFieldTableNames[] = $origFieldTable;
47                $cdb->dropTable( $origFieldTable );
48                $cdb->query( 'ALTER TABLE ' .
49                    $cdb->tableName( $fieldTable ) .
50                    ' RENAME TO ' .
51                    $cdb->tableName( $origFieldTable ) );
52            }
53            if ( is_array( $fieldHelperTables ) ) {
54                foreach ( $fieldHelperTables as $fieldHelperTable ) {
55                    $origFieldHelperTable = str_replace( '__NEXT', '', $fieldHelperTable );
56                    $origFieldHelperTableNames[] = $origFieldHelperTable;
57                    $cdb->dropTable( $origFieldHelperTable );
58                    $cdb->query( 'ALTER TABLE ' .
59                        $cdb->tableName( $fieldHelperTable ) .
60                        ' RENAME TO ' .
61                        $cdb->tableName( $origFieldHelperTable ) );
62                }
63            }
64
65            $cdb->dropTable( $mainTable );
66            $cdb->query( 'ALTER TABLE ' .
67                $cdb->tableName( $mainTable . '__NEXT' ) .
68                ' RENAME TO ' . $cdb->tableName( $mainTable ) );
69
70            $cdb->commit();
71        } catch ( Exception $e ) {
72            throw new MWException( "Caught exception ($e) while trying to switch in replacement for Cargo table. "
73            . "Please make sure that your database user account has the DROP permission." );
74        }
75
76        $dbw = CargoUtils::getMainDBForWrite();
77        $dbw->delete( 'cargo_tables', [ 'main_table' => $mainTable ] );
78        $dbw->delete( 'cargo_pages', [ 'table_name' => $mainTable ] );
79        $dbw->update( 'cargo_tables', [ 'main_table' => $mainTable ], [ 'main_table' => $mainTable . '__NEXT' ] );
80        $dbw->update(
81            'cargo_tables',
82            [
83                'field_tables' => serialize( $origFieldTableNames ),
84                'field_helper_tables' => serialize( $origFieldHelperTableNames )
85            ],
86            [ 'main_table' => $mainTable ]
87        );
88        $dbw->update( 'cargo_pages', [ 'table_name' => $mainTable ], [ 'table_name' => $mainTable . '__NEXT' ] );
89
90        CargoUtils::logTableAction( 'replacetable', $mainTable, $user );
91    }
92
93    public function execute( $subpage = false ) {
94        $this->checkPermissions();
95
96        $out = $this->getOutput();
97        $tableName = $subpage;
98        $out->enableOOUI();
99
100        $this->setHeaders();
101        if ( $tableName == '' ) {
102            CargoUtils::displayErrorMessage( $out, $this->msg( "cargo-notable" ) );
103            return true;
104        }
105
106        // Make sure that this table, and its replacement, both exist.
107        $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
108        $dbr = $lb->getConnectionRef( DB_REPLICA );
109        $res = $dbr->select( 'cargo_tables', [ 'main_table', 'field_tables', 'field_helper_tables' ],
110            [ 'main_table' => $tableName ] );
111        if ( $res->numRows() == 0 ) {
112            CargoUtils::displayErrorMessage( $out, $this->msg( "cargo-unknowntable", $tableName ) );
113            return true;
114        }
115        $res = $dbr->select( 'cargo_tables', [ 'main_table', 'field_tables', 'field_helper_tables' ],
116            [ 'main_table' => $tableName . '__NEXT' ] );
117        if ( $res->numRows() == 0 ) {
118            CargoUtils::displayErrorMessage( $out, $this->msg( "cargo-unknowntable", $tableName . "__NEXT" ) );
119            return true;
120        }
121
122        $ctPage = CargoUtils::getSpecialPage( 'CargoTables' );
123        $row = $res->fetchRow();
124        $fieldTables = unserialize( $row['field_tables'] );
125        $fieldHelperTables = unserialize( $row['field_helper_tables'] );
126
127        if ( $this->getRequest()->getCheck( 'switch' ) ) {
128            self::switchInTableReplacement( $tableName, $fieldTables, $fieldHelperTables, $this->getUser() );
129            $text = Html::element( 'p', null, $this->msg( 'cargo-switchtables-success', $tableName )->parse() ) . "\n";
130            $tablesLink = CargoUtils::makeLink( $this->getLinkRenderer(),
131                $ctPage->getPageTitle(), $ctPage->getDescription() );
132            $text .= Html::rawElement( 'p', null, $this->msg( 'returnto', $tablesLink )->text() );
133            $out->addHTML( $text );
134            return true;
135        }
136
137        $ctURL = $ctPage->getPageTitle()->getLocalURL();
138        $tableLink = Html::element( 'a', [ 'href' => "$ctURL/$tableName", ], $tableName );
139
140        $text = Html::rawElement( 'p', null, $this->msg( 'cargo-switchtables-confirm', $tableLink )->text() );
141        $out->addHTML( $text );
142
143        $htmlForm = HTMLForm::factory( 'ooui', [], $this->getContext() );
144        $htmlForm
145            ->setSubmitName( 'switch' )
146            ->setSubmitTextMsg( 'cargo-switchtables-switch' )
147            ->prepareForm()
148            ->displayForm( false );
149
150        return true;
151    }
152
153}