Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
FlowFixLinks
0.00% covered (danger)
0.00%
0 / 72
0.00% covered (danger)
0.00%
0 / 5
72
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getUpdateKey
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doDBUpdates
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 removeVirtualPages
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 rebuildCoreTables
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace Flow\Maintenance;
4
5use BatchRowIterator;
6use Flow\Container;
7use Flow\Data\ObjectManager;
8use Flow\LinksTableUpdater;
9use Flow\Model\Workflow;
10use LoggedUpdateMaintenance;
11use MediaWiki\WikiMap\WikiMap;
12
13$IP = getenv( 'MW_INSTALL_PATH' );
14if ( $IP === false ) {
15    $IP = __DIR__ . '/../../..';
16}
17
18require_once "$IP/maintenance/Maintenance.php";
19
20/**
21 * Fixes Flow References & entries in categorylinks & related tables.
22 *
23 * @ingroup Maintenance
24 */
25class FlowFixLinks extends LoggedUpdateMaintenance {
26    public function __construct() {
27        parent::__construct();
28
29        $this->addDescription( 'Fixes Flow References & entries in categorylinks & related tables' );
30
31        $this->setBatchSize( 300 );
32
33        $this->requireExtension( 'Flow' );
34    }
35
36    protected function getUpdateKey() {
37        return 'FlowFixLinks:v2';
38    }
39
40    protected function doDBUpdates() {
41        // disable Echo notifications for this script
42        global $wgEchoNotifications;
43
44        $wgEchoNotifications = [];
45
46        $this->removeVirtualPages();
47        $this->rebuildCoreTables();
48
49        $this->output( "Completed\n" );
50
51        return true;
52    }
53
54    protected function removeVirtualPages() {
55        /** @var ObjectManager $storage */
56        $storage = Container::get( 'storage.wiki_reference' );
57        $links = $storage->find( [
58            'ref_src_wiki' => WikiMap::getCurrentWikiId(),
59            'ref_target_namespace' => [ -1, -2 ],
60        ] );
61        if ( $links ) {
62            $storage->multiRemove( $links, [] );
63        }
64
65        $this->output( "Removed " . count( $links ) . " links to special pages.\n" );
66    }
67
68    protected function rebuildCoreTables() {
69        $dbw = $this->getPrimaryDB();
70        $dbr = Container::get( 'db.factory' )->getDB( DB_REPLICA );
71        /** @var LinksTableUpdater $linksTableUpdater */
72        $linksTableUpdater = Container::get( 'reference.updater.links-tables' );
73
74        $iterator = new BatchRowIterator( $dbr, 'flow_workflow', 'workflow_id', $this->getBatchSize() );
75        $iterator->setFetchColumns( [ '*' ] );
76        $iterator->addConditions( [ 'workflow_wiki' => WikiMap::getCurrentWikiId() ] );
77        $iterator->setCaller( __METHOD__ );
78
79        $count = 0;
80        foreach ( $iterator as $rows ) {
81            $this->beginTransaction( $dbw, __METHOD__ );
82
83            foreach ( $rows as $row ) {
84                $workflow = Workflow::fromStorageRow( (array)$row );
85                $id = $workflow->getArticleTitle()->getArticleID();
86
87                // delete existing links from DB
88                $dbw->newDeleteQueryBuilder()
89                    ->deleteFrom( 'pagelinks' )
90                    ->where( [ 'pl_from' => $id ] )
91                    ->caller( __METHOD__ )
92                    ->execute();
93                $dbw->newDeleteQueryBuilder()
94                    ->deleteFrom( 'imagelinks' )
95                    ->where( [ 'il_from' => $id ] )
96                    ->caller( __METHOD__ )
97                    ->execute();
98                $dbw->newDeleteQueryBuilder()
99                    ->deleteFrom( 'categorylinks' )
100                    ->where( [ 'cl_from' => $id ] )
101                    ->caller( __METHOD__ )
102                    ->execute();
103                $dbw->newDeleteQueryBuilder()
104                    ->deleteFrom( 'templatelinks' )
105                    ->where( [ 'tl_from' => $id ] )
106                    ->caller( __METHOD__ )
107                    ->execute();
108                $dbw->newDeleteQueryBuilder()
109                    ->deleteFrom( 'externallinks' )
110                    ->where( [ 'el_from' => $id ] )
111                    ->caller( __METHOD__ )
112                    ->execute();
113                $dbw->newDeleteQueryBuilder()
114                    ->deleteFrom( 'langlinks' )
115                    ->where( [ 'll_from' => $id ] )
116                    ->caller( __METHOD__ )
117                    ->execute();
118                $dbw->newDeleteQueryBuilder()
119                    ->deleteFrom( 'iwlinks' )
120                    ->where( [ 'iwl_from' => $id ] )
121                    ->caller( __METHOD__ )
122                    ->execute();
123
124                // regenerate & store those links
125                $linksTableUpdater->doUpdate( $workflow );
126            }
127
128            $this->commitTransaction( $dbw, __METHOD__ );
129
130            $count += count( $rows );
131            $this->output( "Rebuilt links for " . $count . " workflows...\n" );
132            $this->waitForReplication();
133        }
134    }
135}
136
137$maintClass = FlowFixLinks::class;
138require_once RUN_MAINTENANCE_IF_MAIN;