Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
FlowDumpBackup
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 4
272
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
6
 execute
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 dump
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
20
 processOptions
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
56
1<?php
2
3namespace Flow\Maintenance;
4
5use BackupDumper;
6use Flow\Container;
7use Flow\Dump\Exporter;
8use WikiExporter;
9
10$IP = getenv( 'MW_INSTALL_PATH' );
11if ( $IP === false ) {
12    $IP = __DIR__ . '/../../..';
13}
14
15require_once "$IP/maintenance/Maintenance.php";
16require_once "$IP/maintenance/includes/BackupDumper.php";
17
18class FlowDumpBackup extends BackupDumper {
19    /** @var string|null */
20    public $workflowStartId = null;
21    /** @var string|null */
22    public $workflowEndId = null;
23
24    public function __construct( $args = null ) {
25        parent::__construct();
26
27        $this->addDescription( <<<TEXT
28This script dumps the Flow discussion database into an
29XML interchange wrapper format for export.
30
31It can either export only the current revision, or full history.
32
33Although the --full will export all public revisions, non-public revisions
34are removed, and the remaining revisions are renormalized to accomodate this.
35It is recommended that you keep database backups as well.
36
37XML output is sent to stdout; progress reports are sent to stderr.
38TEXT
39        );
40
41        $this->addOption( 'full', 'Dump all revisions of every description/post/summary' );
42        $this->addOption( 'current', 'Dump only the latest revision of every description/post/summary' );
43        $this->addOption( 'pagelist', 'Dump only pages of which the title is included in the file', false, true );
44
45        $this->addOption( 'start', 'Start from page_id n', false, true );
46        $this->addOption( 'end', 'Stop before page_id n (exclusive)', false, true );
47        $this->addOption( 'boardstart', 'Start from board id n', false, true );
48        $this->addOption( 'boardend', 'Stop before board_id n (exclusive)', false, true );
49        $this->addOption( 'skip-header', 'Don\'t output the <mediawiki> header' );
50        $this->addOption( 'skip-footer', 'Don\'t output the </mediawiki> footer' );
51
52        $this->requireExtension( 'Flow' );
53
54        if ( $args ) {
55            $this->loadWithArgv( $args );
56            $this->processOptions();
57        }
58    }
59
60    public function execute() {
61        $this->processOptions();
62
63        if ( $this->hasOption( 'full' ) ) {
64            $this->dump( WikiExporter::FULL );
65        } elseif ( $this->hasOption( 'current' ) ) {
66            $this->dump( WikiExporter::CURRENT );
67        } else {
68            $this->fatalError( 'No valid action specified.' );
69        }
70    }
71
72    /**
73     * @param int $history WikiExporter::FULL or WikiExporter::CURRENT
74     * @param int $text Unused, but exists for compat with parent
75     */
76    public function dump( $history, $text = WikiExporter::TEXT ) {
77        # Notice messages will foul up your XML output even if they're
78        # relatively harmless.
79        if ( ini_get( 'display_errors' ) ) {
80            ini_set( 'display_errors', 'stderr' );
81        }
82
83        $db = Container::get( 'db.factory' )->getDB( DB_REPLICA );
84
85        $services = $this->getServiceContainer();
86        $exporter = new Exporter(
87            $db,
88            $services->getCommentStore(),
89            $services->getHookContainer(),
90            $services->getRevisionStore(),
91            $services->getTitleParser(),
92            $history,
93            WikiExporter::TEXT
94        );
95        $exporter->setOutputSink( $this->sink );
96
97        if ( !$this->skipHeader ) {
98            $exporter->openStream();
99        }
100
101        $workflowIterator = $exporter->getWorkflowIterator( $this->pages, $this->startId, $this->endId,
102            $this->workflowStartId, $this->workflowEndId );
103
104        $exporter->dump( $workflowIterator );
105
106        if ( !$this->skipFooter ) {
107            $exporter->closeStream();
108        }
109
110        $this->report( true );
111    }
112
113    public function processOptions() {
114        parent::processOptions();
115
116        // Evaluate options specific to this class
117        $this->reporting = !$this->hasOption( 'quiet' );
118
119        if ( $this->hasOption( 'pagelist' ) ) {
120            $filename = $this->getOption( 'pagelist' );
121            $pages = file( $filename );
122            if ( $pages === false ) {
123                $this->fatalError( "Unable to open file {$filename}\n" );
124            }
125            $pages = array_map( 'trim', $pages );
126            $this->pages = array_filter(
127                $pages,
128                static function ( $x ) {
129                    return $x !== '';
130                }
131            );
132        }
133
134        if ( $this->hasOption( 'start' ) ) {
135            $this->startId = intval( $this->getOption( 'start' ) );
136        }
137
138        if ( $this->hasOption( 'end' ) ) {
139            $this->endId = intval( $this->getOption( 'end' ) );
140        }
141
142        if ( $this->hasOption( 'boardstart' ) ) {
143            $this->workflowStartId = $this->getOption( 'boardstart' );
144        }
145
146        if ( $this->hasOption( 'boardend' ) ) {
147            $this->workflowEndId = $this->getOption( 'boardend' );
148        }
149
150        $this->skipHeader = $this->hasOption( 'skip-header' );
151        $this->skipFooter = $this->hasOption( 'skip-footer' );
152    }
153}
154
155$maintClass = FlowDumpBackup::class;
156require_once RUN_MAINTENANCE_IF_MAIN;