Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 87
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 / 87
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 / 42
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
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();
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 );
46                $cdb->query( 'ALTER TABLE ' .
47                    $cdb->tableName( $fieldTable ) .
48                    ' RENAME TO ' .
49                    $cdb->tableName( $origFieldTable ) );
50            }
51            if ( is_array( $fieldHelperTables ) ) {
52                foreach ( $fieldHelperTables as $fieldHelperTable ) {
53                    $origFieldHelperTable = str_replace( '__NEXT', '', $fieldHelperTable );
54                    $origFieldHelperTableNames[] = $origFieldHelperTable;
55                    $cdb->dropTable( $origFieldHelperTable );
56                    $cdb->query( 'ALTER TABLE ' .
57                        $cdb->tableName( $fieldHelperTable ) .
58                        ' RENAME TO ' .
59                        $cdb->tableName( $origFieldHelperTable ) );
60                }
61            }
62
63            $cdb->dropTable( $mainTable );
64            $cdb->query( 'ALTER TABLE ' .
65                $cdb->tableName( $mainTable . '__NEXT' ) .
66                ' RENAME TO ' . $cdb->tableName( $mainTable ) );
67
68            $cdb->commit();
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 ] );
76        $dbw->delete( 'cargo_pages', [ 'table_name' => $mainTable ] );
77        $dbw->update( 'cargo_tables', [ 'main_table' => $mainTable ], [ 'main_table' => $mainTable . '__NEXT' ] );
78        $dbw->update(
79            'cargo_tables',
80            [
81                'field_tables' => serialize( $origFieldTableNames ),
82                'field_helper_tables' => serialize( $origFieldHelperTableNames )
83            ],
84            [ 'main_table' => $mainTable ]
85        );
86        $dbw->update( 'cargo_pages', [ 'table_name' => $mainTable ], [ 'table_name' => $mainTable . '__NEXT' ] );
87
88        CargoUtils::logTableAction( 'replacetable', $mainTable, $user );
89    }
90
91    public function execute( $subpage = false ) {
92        $this->checkPermissions();
93
94        $out = $this->getOutput();
95        $tableName = $subpage;
96        $out->enableOOUI();
97
98        $this->setHeaders();
99        if ( $tableName == '' ) {
100            CargoUtils::displayErrorMessage( $out, $this->msg( "cargo-notable" ) );
101            return true;
102        }
103
104        // Make sure that this table, and its replacement, both exist.
105        $dbr = CargoUtils::getMainDBForRead();
106        $res = $dbr->select( 'cargo_tables', [ 'main_table', 'field_tables', 'field_helper_tables' ],
107            [ 'main_table' => $tableName ] );
108        if ( $res->numRows() == 0 ) {
109            CargoUtils::displayErrorMessage( $out, $this->msg( "cargo-unknowntable", $tableName ) );
110            return true;
111        }
112        $res = $dbr->select( 'cargo_tables', [ 'main_table', 'field_tables', 'field_helper_tables' ],
113            [ 'main_table' => $tableName . '__NEXT' ] );
114        if ( $res->numRows() == 0 ) {
115            CargoUtils::displayErrorMessage( $out, $this->msg( "cargo-unknowntable", $tableName . "__NEXT" ) );
116            return true;
117        }
118
119        $ctPage = CargoUtils::getSpecialPage( 'CargoTables' );
120        $row = $res->fetchRow();
121        $fieldTables = unserialize( $row['field_tables'] );
122        $fieldHelperTables = unserialize( $row['field_helper_tables'] );
123
124        if ( $this->getRequest()->getCheck( 'switch' ) ) {
125            self::switchInTableReplacement( $tableName, $fieldTables, $fieldHelperTables, $this->getUser() );
126            $text = Html::element( 'p', null, $this->msg( 'cargo-switchtables-success', $tableName )->parse() ) . "\n";
127            $tablesLink = CargoUtils::makeLink( $this->getLinkRenderer(),
128                $ctPage->getPageTitle(), $ctPage->getDescription() );
129            $text .= Html::rawElement( 'p', null, $this->msg( 'returnto', $tablesLink )->text() );
130            $out->addHTML( $text );
131            return true;
132        }
133
134        $ctURL = $ctPage->getPageTitle()->getLocalURL();
135        $tableLink = Html::element( 'a', [ 'href' => "$ctURL/$tableName", ], $tableName );
136
137        $text = Html::rawElement( 'p', null, $this->msg( 'cargo-switchtables-confirm', $tableLink )->text() );
138        $out->addHTML( $text );
139
140        $htmlForm = HTMLForm::factory( 'ooui', [], $this->getContext() );
141        $htmlForm
142            ->setSubmitName( 'switch' )
143            ->setSubmitTextMsg( 'cargo-switchtables-switch' )
144            ->prepareForm()
145            ->displayForm( false );
146
147        return true;
148    }
149
150}