Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
PurgeUnusedProjects
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 2
72
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 1
56
1<?php
2/**
3 * This script will remove any unused projects from the page_assessments_projects
4 * table. This may include WikiProjects that have been renamed or retired, or
5 * projects that were used in an assessment by mistake or for testing.
6 */
7
8use MediaWiki\Maintenance\Maintenance;
9
10$IP = getenv( 'MW_INSTALL_PATH' );
11if ( $IP === false ) {
12    $IP = __DIR__ . '/../../..';
13}
14require_once "$IP/maintenance/Maintenance.php";
15
16class PurgeUnusedProjects extends Maintenance {
17
18    public function __construct() {
19        parent::__construct();
20        $this->requireExtension( 'PageAssessments' );
21        $this->addDescription( "Purge unused projects from the page_assessments_projects table" );
22        $this->addOption( 'dry-run',
23            "Show how many projects would be deleted, but don't actually purge them." );
24    }
25
26    public function execute() {
27        $dbw = $this->getDB( DB_PRIMARY );
28        $dbr = $this->getDB( DB_REPLICA );
29        // Count all the projects
30        $initialCount = $dbr->newSelectQueryBuilder()
31            ->select( 'COUNT(*)' )
32            ->from( 'page_assessments_projects' )
33            ->caller( __METHOD__ )
34            ->fetchField();
35        $this->output( "Projects before purge: $initialCount\n" );
36
37        // Build a list of all the projects that are parents of other projects
38        $projectIds1 = [];
39        $res = $dbr->newSelectQueryBuilder()
40            ->select( 'pap_parent_id' )
41            ->distinct()
42            ->from( 'page_assessments_projects' )
43            ->caller( __METHOD__ )
44            ->fetchResultSet();
45        foreach ( $res as $row ) {
46            if ( $row->pap_parent_id ) {
47                $projectIds1[] = $row->pap_parent_id;
48            }
49        }
50
51        // Build a list of all the projects that are used in assessments
52        $projectIds2 = [];
53        $res = $dbr->newSelectQueryBuilder()
54            ->select( 'pa_project_id' )
55            ->distinct()
56            ->from( 'page_assessments' )
57            ->caller( __METHOD__ )
58            ->fetchResultset();
59        foreach ( $res as $row ) {
60            if ( $row->pa_project_id ) {
61                $projectIds2[] = $row->pa_project_id;
62            }
63        }
64
65        // Combine the two lists
66        $usedProjectIds = array_values( array_unique( array_merge( $projectIds1, $projectIds2 ) ) );
67
68        // Protect against lack of projects in some environments - T219935
69        if ( !count( $usedProjectIds ) ) {
70            $this->output( "No projects found.\nDone.\n" );
71            return;
72        }
73
74        if ( $this->hasOption( 'dry-run' ) ) {
75            $finalCount = count( $usedProjectIds );
76        } else {
77            $this->output( "Purging unused projects from page_assessments_projects...\n" );
78            // Delete all the projects that aren't used in any current assessments
79            // and aren't parents of other projects.
80            $conds = $dbr->expr( 'pap_project_id', '!=', $usedProjectIds );
81            $dbw->newDeleteQueryBuilder()
82                ->deleteFrom( 'page_assessments_projects' )
83                ->where( $conds )
84                ->caller( __METHOD__ )
85                ->execute();
86            $this->output( "Done.\n" );
87            $this->waitForReplication();
88            // Recount all the projects
89            $finalCount = $dbr->newSelectQueryBuilder()
90                ->select( 'COUNT(*)' )
91                ->from( 'page_assessments_projects' )
92                ->caller( __METHOD__ )
93                ->fetchField();
94        }
95        $this->output( "Projects after purge: $finalCount\n" );
96    }
97
98}
99
100$maintClass = PurgeUnusedProjects::class;
101require_once RUN_MAINTENANCE_IF_MAIN;