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