MediaWiki master
cleanupPreferences.php
Go to the documentation of this file.
1<?php
27require_once __DIR__ . '/Maintenance.php';
28
33
40 public function __construct() {
41 parent::__construct();
42 $this->addDescription( 'Clean up hidden preferences or removed preferences' );
43 $this->setBatchSize( 50 );
44 $this->addOption( 'dry-run', 'Print debug info instead of actually deleting' );
45 $this->addOption( 'hidden', 'Drop hidden preferences ($wgHiddenPrefs)' );
46 $this->addOption( 'unknown',
47 'Drop unknown preferences (not in $wgDefaultUserOptions or prefixed with "userjs-")' );
48 }
49
58 public function execute() {
59 $dbr = $this->getReplicaDB();
60 $hidden = $this->hasOption( 'hidden' );
61 $unknown = $this->hasOption( 'unknown' );
62
63 if ( !$hidden && !$unknown ) {
64 $this->output( "Did not select one of --hidden, --unknown, exiting\n" );
65 return;
66 }
67
68 // Remove hidden prefs. Iterate over them to avoid the IN on a large table
69 if ( $hidden ) {
70 $hiddenPrefs = $this->getConfig()->get( MainConfigNames::HiddenPrefs );
71 if ( !$hiddenPrefs ) {
72 $this->output( "No hidden preferences, skipping\n" );
73 }
74 foreach ( $hiddenPrefs as $hiddenPref ) {
75 $this->deleteByWhere(
76 $dbr,
77 'Dropping hidden preferences',
78 [ 'up_property' => $hiddenPref ]
79 );
80 }
81 }
82
83 // Remove unknown preferences. Special-case 'userjs-' as we can't control those names.
84 if ( $unknown ) {
85 $defaultUserOptions = $this->getServiceContainer()->getUserOptionsLookup()->getDefaultOptions( null );
86 $where = [
87 $dbr->expr( 'up_property', IExpression::NOT_LIKE,
88 new LikeValue( 'userjs-', $dbr->anyString() ) ),
89 $dbr->expr( 'up_property', IExpression::NOT_LIKE,
90 new LikeValue( UserOptionsLookup::LOCAL_EXCEPTION_SUFFIX, $dbr->anyString() ) ),
91 $dbr->expr( 'up_property', '!=', array_keys( $defaultUserOptions ) ),
92 ];
93 // Allow extensions to add to the where clause to prevent deletion of their own prefs.
94 $this->getHookRunner()->onDeleteUnknownPreferences( $where, $dbr );
95 $this->deleteByWhere( $dbr, 'Dropping unknown preferences', $where );
96 }
97 }
98
99 private function deleteByWhere( $dbr, $startMessage, $where ) {
100 $this->output( $startMessage . "...\n" );
101 $dryRun = $this->hasOption( 'dry-run' );
102
103 $iterator = new BatchRowIterator(
104 $dbr,
105 'user_properties',
106 [ 'up_user', 'up_property' ],
107 $this->getBatchSize()
108 );
109 if ( $dryRun ) {
110 $iterator->setFetchColumns( [ 'up_user', 'up_property', 'up_value' ] );
111 } else {
112 $iterator->setFetchColumns( [ 'up_user', 'up_property' ] );
113 }
114 $iterator->addConditions( $where );
115 $iterator->setCaller( __METHOD__ );
116
117 $dbw = $this->getPrimaryDB();
118 $total = 0;
119 foreach ( $iterator as $batch ) {
120 $numRows = count( $batch );
121 $total += $numRows;
122 // Progress or something
123 $this->output( "..doing $numRows entries\n" );
124
125 // Delete our batch, then wait
126 $deleteWhere = [];
127 foreach ( $batch as $row ) {
128 if ( $dryRun ) {
129 $this->output(
130 " DRY RUN, would drop: " .
131 "[up_user] => '{$row->up_user}' " .
132 "[up_property] => '{$row->up_property}' " .
133 "[up_value] => '{$row->up_value}'\n"
134 );
135 continue;
136 }
137 $deleteWhere[$row->up_user][$row->up_property] = true;
138 }
139 if ( $deleteWhere && !$dryRun ) {
140 $dbw->newDeleteQueryBuilder()
141 ->deleteFrom( 'user_properties' )
142 ->where( $dbw->makeWhereFrom2d( $deleteWhere, 'up_user', 'up_property' ) )
143 ->caller( __METHOD__ )->execute();
144
145 $this->waitForReplication();
146 }
147 }
148 $this->output( "DONE! (handled $total entries)\n" );
149 }
150}
151
152$maintClass = CleanupPreferences::class; // Tells it to run the class
153require_once RUN_MAINTENANCE_IF_MAIN;
Allows iterating a large number of rows in batches transparently.
Maintenance script that removes unused preferences from the database.
__construct()
Default constructor.
execute()
We will do this in three passes 1) The easiest is to drop the hidden preferences from the database.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
output( $out, $channel=null)
Throw some output to the user.
getHookRunner()
Get a HookRunner for running core hooks.
waitForReplication()
Wait for replica DBs to catch up.
hasOption( $name)
Checks to see if a particular option was set.
getServiceContainer()
Returns the main service container.
getBatchSize()
Returns batch size.
addDescription( $text)
Set the description text.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
setBatchSize( $s=0)
A class containing constants representing the names of configuration variables.
Provides access to user options.
Content of like value.
Definition LikeValue.php:14