Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 79
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 / 73
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 / 54
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        $lbFactory = $this->getServiceContainer()->getDBLoadBalancerFactory();
80
81        $count = 0;
82        foreach ( $iterator as $rows ) {
83            $this->beginTransaction( $dbw, __METHOD__ );
84
85            foreach ( $rows as $row ) {
86                $workflow = Workflow::fromStorageRow( (array)$row );
87                $id = $workflow->getArticleTitle()->getArticleID();
88
89                // delete existing links from DB
90                $dbw->newDeleteQueryBuilder()
91                    ->deleteFrom( 'pagelinks' )
92                    ->where( [ 'pl_from' => $id ] )
93                    ->caller( __METHOD__ )
94                    ->execute();
95                $dbw->newDeleteQueryBuilder()
96                    ->deleteFrom( 'imagelinks' )
97                    ->where( [ 'il_from' => $id ] )
98                    ->caller( __METHOD__ )
99                    ->execute();
100                $dbw->newDeleteQueryBuilder()
101                    ->deleteFrom( 'categorylinks' )
102                    ->where( [ 'cl_from' => $id ] )
103                    ->caller( __METHOD__ )
104                    ->execute();
105                $dbw->newDeleteQueryBuilder()
106                    ->deleteFrom( 'templatelinks' )
107                    ->where( [ 'tl_from' => $id ] )
108                    ->caller( __METHOD__ )
109                    ->execute();
110                $dbw->newDeleteQueryBuilder()
111                    ->deleteFrom( 'externallinks' )
112                    ->where( [ 'el_from' => $id ] )
113                    ->caller( __METHOD__ )
114                    ->execute();
115                $dbw->newDeleteQueryBuilder()
116                    ->deleteFrom( 'langlinks' )
117                    ->where( [ 'll_from' => $id ] )
118                    ->caller( __METHOD__ )
119                    ->execute();
120                $dbw->newDeleteQueryBuilder()
121                    ->deleteFrom( 'iwlinks' )
122                    ->where( [ 'iwl_from' => $id ] )
123                    ->caller( __METHOD__ )
124                    ->execute();
125
126                // regenerate & store those links
127                $linksTableUpdater->doUpdate( $workflow );
128            }
129
130            $this->commitTransaction( $dbw, __METHOD__ );
131
132            $count += count( $rows );
133            $this->output( "Rebuilt links for " . $count . " workflows...\n" );
134            $lbFactory->waitForReplication();
135        }
136    }
137}
138
139$maintClass = FlowFixLinks::class;
140require_once RUN_MAINTENANCE_IF_MAIN;