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