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 Flow\Container;
6use Flow\Data\ObjectManager;
7use Flow\LinksTableUpdater;
8use Flow\Model\Workflow;
9use MediaWiki\Deferred\LinksUpdate\LinksTable;
10use MediaWiki\Maintenance\LoggedUpdateMaintenance;
11use MediaWiki\Utils\BatchRowIterator;
12use MediaWiki\WikiMap\WikiMap;
13
14$IP = getenv( 'MW_INSTALL_PATH' );
15if ( $IP === false ) {
16    $IP = __DIR__ . '/../../..';
17}
18
19require_once "$IP/maintenance/Maintenance.php";
20
21/**
22 * Fixes Flow References & entries in categorylinks & related tables.
23 *
24 * @ingroup Maintenance
25 */
26class FlowFixLinks extends LoggedUpdateMaintenance {
27    public function __construct() {
28        parent::__construct();
29
30        $this->addDescription( 'Fixes Flow References & entries in categorylinks & related tables' );
31
32        $this->setBatchSize( 300 );
33
34        $this->requireExtension( 'Flow' );
35    }
36
37    protected function getUpdateKey() {
38        return 'FlowFixLinks:v2';
39    }
40
41    protected function doDBUpdates() {
42        // disable Echo notifications for this script
43        global $wgEchoNotifications;
44
45        $wgEchoNotifications = [];
46
47        $this->removeVirtualPages();
48        $this->rebuildCoreTables();
49
50        $this->output( "Completed\n" );
51
52        return true;
53    }
54
55    protected function removeVirtualPages() {
56        /** @var ObjectManager $storage */
57        $storage = Container::get( 'storage.wiki_reference' );
58        $links = $storage->find( [
59            'ref_src_wiki' => WikiMap::getCurrentWikiId(),
60            'ref_target_namespace' => [ -1, -2 ],
61        ] );
62        if ( $links ) {
63            $storage->multiRemove( $links, [] );
64        }
65
66        $this->output( "Removed " . count( $links ) . " links to special pages.\n" );
67    }
68
69    protected function rebuildCoreTables() {
70        $dbProvider = $this->getServiceContainer()->getConnectionProvider();
71        $dbw = $dbProvider->getPrimaryDatabase( LinksTable::VIRTUAL_DOMAIN );
72        $dbr = Container::get( 'db.factory' )->getDB( DB_REPLICA );
73        /** @var LinksTableUpdater $linksTableUpdater */
74        $linksTableUpdater = Container::get( 'reference.updater.links-tables' );
75
76        $iterator = new BatchRowIterator( $dbr, 'flow_workflow', 'workflow_id', $this->getBatchSize() );
77        $iterator->setFetchColumns( [ '*' ] );
78        $iterator->addConditions( [ 'workflow_wiki' => WikiMap::getCurrentWikiId() ] );
79        $iterator->setCaller( __METHOD__ );
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            $this->waitForReplication();
135        }
136    }
137}
138
139$maintClass = FlowFixLinks::class;
140require_once RUN_MAINTENANCE_IF_MAIN;