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