| Total Complexity | 40 |
| Total Lines | 261 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Complex classes like Scheduler often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Scheduler, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 10 | class Scheduler { |
||
| 11 | public $checkPeriod = 12; //How often to check for updates (in hours). |
||
| 12 | public $throttleRedundantChecks = false; //Check less often if we already know that an update is available. |
||
| 13 | public $throttledCheckPeriod = 72; |
||
| 14 | |||
| 15 | protected $hourlyCheckHooks = array('load-update.php'); |
||
| 16 | |||
| 17 | /** |
||
| 18 | * @var UpdateChecker |
||
| 19 | */ |
||
| 20 | protected $updateChecker; |
||
| 21 | |||
| 22 | private $cronHook = null; |
||
| 23 | |||
| 24 | /** |
||
| 25 | * Scheduler constructor. |
||
| 26 | * |
||
| 27 | * @param UpdateChecker $updateChecker |
||
| 28 | * @param int $checkPeriod How often to check for updates (in hours). |
||
| 29 | * @param array $hourlyHooks |
||
| 30 | */ |
||
| 31 | public function __construct($updateChecker, $checkPeriod, $hourlyHooks = array('load-plugins.php')) { |
||
| 32 | $this->updateChecker = $updateChecker; |
||
| 33 | $this->checkPeriod = $checkPeriod; |
||
| 34 | |||
| 35 | //Set up the periodic update checks |
||
| 36 | $this->cronHook = $this->updateChecker->getUniqueName('cron_check_updates'); |
||
| 37 | if ( $this->checkPeriod > 0 ){ |
||
| 38 | |||
| 39 | //Trigger the check via Cron. |
||
| 40 | //Try to use one of the default schedules if possible as it's less likely to conflict |
||
| 41 | //with other plugins and their custom schedules. |
||
| 42 | $defaultSchedules = array( |
||
| 43 | 1 => 'hourly', |
||
| 44 | 12 => 'twicedaily', |
||
| 45 | 24 => 'daily', |
||
| 46 | ); |
||
| 47 | if ( array_key_exists($this->checkPeriod, $defaultSchedules) ) { |
||
| 48 | $scheduleName = $defaultSchedules[$this->checkPeriod]; |
||
| 49 | } else { |
||
| 50 | //Use a custom cron schedule. |
||
| 51 | $scheduleName = 'every' . $this->checkPeriod . 'hours'; |
||
| 52 | add_filter('cron_schedules', array($this, '_addCustomSchedule')); |
||
| 53 | } |
||
| 54 | |||
| 55 | if ( !wp_next_scheduled($this->cronHook) && !defined('WP_INSTALLING') ) { |
||
| 56 | //Randomly offset the schedule to help prevent update server traffic spikes. Without this |
||
| 57 | //most checks may happen during times of day when people are most likely to install new plugins. |
||
| 58 | $upperLimit = max($this->checkPeriod * 3600 - 15 * 60, 1); |
||
| 59 | if ( function_exists('wp_rand') ) { |
||
| 60 | $randomOffset = wp_rand(0, $upperLimit); |
||
| 61 | } else { |
||
| 62 | //This constructor may be called before wp_rand() is available. |
||
| 63 | //phpcs:ignore WordPress.WP.AlternativeFunctions.rand_rand |
||
| 64 | $randomOffset = rand(0, $upperLimit); |
||
| 65 | } |
||
| 66 | $firstCheckTime = time() - $randomOffset; |
||
| 67 | $firstCheckTime = apply_filters( |
||
| 68 | $this->updateChecker->getUniqueName('first_check_time'), |
||
| 69 | $firstCheckTime |
||
| 70 | ); |
||
| 71 | wp_schedule_event($firstCheckTime, $scheduleName, $this->cronHook); |
||
| 72 | } |
||
| 73 | add_action($this->cronHook, array($this, 'maybeCheckForUpdates')); |
||
| 74 | |||
| 75 | //In case Cron is disabled or unreliable, we also manually trigger |
||
| 76 | //the periodic checks while the user is browsing the Dashboard. |
||
| 77 | add_action( 'admin_init', array($this, 'maybeCheckForUpdates') ); |
||
| 78 | |||
| 79 | //Like WordPress itself, we check more often on certain pages. |
||
| 80 | /** @see wp_update_plugins */ |
||
| 81 | add_action('load-update-core.php', array($this, 'maybeCheckForUpdates')); |
||
| 82 | //"load-update.php" and "load-plugins.php" or "load-themes.php". |
||
| 83 | $this->hourlyCheckHooks = array_merge($this->hourlyCheckHooks, $hourlyHooks); |
||
| 84 | foreach($this->hourlyCheckHooks as $hook) { |
||
| 85 | add_action($hook, array($this, 'maybeCheckForUpdates')); |
||
| 86 | } |
||
| 87 | //This hook fires after a bulk update is complete. |
||
| 88 | add_action('upgrader_process_complete', array($this, 'upgraderProcessComplete'), 11, 2); |
||
| 89 | |||
| 90 | } else { |
||
| 91 | //Periodic checks are disabled. |
||
| 92 | wp_clear_scheduled_hook($this->cronHook); |
||
| 93 | } |
||
| 94 | } |
||
| 95 | |||
| 96 | /** |
||
| 97 | * Runs upon the WP action upgrader_process_complete. |
||
| 98 | * |
||
| 99 | * We look at the parameters to decide whether to call maybeCheckForUpdates() or not. |
||
| 100 | * We also check if the update checker has been removed by the update. |
||
| 101 | * |
||
| 102 | * @param \WP_Upgrader $upgrader WP_Upgrader instance |
||
| 103 | * @param array $upgradeInfo extra information about the upgrade |
||
| 104 | */ |
||
| 105 | public function upgraderProcessComplete( |
||
| 158 | } |
||
| 159 | |||
| 160 | /** |
||
| 161 | * Check for updates if the configured check interval has already elapsed. |
||
| 162 | * Will use a shorter check interval on certain admin pages like "Dashboard -> Updates" or when doing cron. |
||
| 163 | * |
||
| 164 | * You can override the default behaviour by using the "puc_check_now-$slug" filter. |
||
| 165 | * The filter callback will be passed three parameters: |
||
| 166 | * - Current decision. TRUE = check updates now, FALSE = don't check now. |
||
| 167 | * - Last check time as a Unix timestamp. |
||
| 168 | * - Configured check period in hours. |
||
| 169 | * Return TRUE to check for updates immediately, or FALSE to cancel. |
||
| 170 | * |
||
| 171 | * This method is declared public because it's a hook callback. Calling it directly is not recommended. |
||
| 172 | */ |
||
| 173 | public function maybeCheckForUpdates() { |
||
| 174 | if ( empty($this->checkPeriod) ){ |
||
| 175 | return; |
||
| 176 | } |
||
| 177 | |||
| 178 | $state = $this->updateChecker->getUpdateState(); |
||
| 179 | $shouldCheck = ($state->timeSinceLastCheck() >= $this->getEffectiveCheckPeriod()); |
||
| 180 | |||
| 181 | //Let plugin authors substitute their own algorithm. |
||
| 182 | $shouldCheck = apply_filters( |
||
| 183 | $this->updateChecker->getUniqueName('check_now'), |
||
| 184 | $shouldCheck, |
||
| 185 | $state->getLastCheck(), |
||
| 186 | $this->checkPeriod |
||
| 187 | ); |
||
| 188 | |||
| 189 | if ( $shouldCheck ) { |
||
| 190 | $this->updateChecker->checkForUpdates(); |
||
| 191 | } |
||
| 192 | } |
||
| 193 | |||
| 194 | /** |
||
| 195 | * Calculate the actual check period based on the current status and environment. |
||
| 196 | * |
||
| 197 | * @return int Check period in seconds. |
||
| 198 | */ |
||
| 199 | protected function getEffectiveCheckPeriod() { |
||
| 200 | $currentFilter = current_filter(); |
||
| 201 | if ( in_array($currentFilter, array('load-update-core.php', 'upgrader_process_complete')) ) { |
||
| 202 | //Check more often when the user visits "Dashboard -> Updates" or does a bulk update. |
||
| 203 | $period = 60; |
||
| 204 | } else if ( in_array($currentFilter, $this->hourlyCheckHooks) ) { |
||
| 205 | //Also check more often on /wp-admin/update.php and the "Plugins" or "Themes" page. |
||
| 206 | $period = 3600; |
||
| 207 | } else if ( $this->throttleRedundantChecks && ($this->updateChecker->getUpdate() !== null) ) { |
||
| 208 | //Check less frequently if it's already known that an update is available. |
||
| 209 | $period = $this->throttledCheckPeriod * 3600; |
||
| 210 | } else if ( defined('DOING_CRON') && constant('DOING_CRON') ) { |
||
| 211 | //WordPress cron schedules are not exact, so lets do an update check even |
||
| 212 | //if slightly less than $checkPeriod hours have elapsed since the last check. |
||
| 213 | $cronFuzziness = 20 * 60; |
||
| 214 | $period = $this->checkPeriod * 3600 - $cronFuzziness; |
||
| 215 | } else { |
||
| 216 | $period = $this->checkPeriod * 3600; |
||
| 217 | } |
||
| 218 | |||
| 219 | return $period; |
||
| 220 | } |
||
| 221 | |||
| 222 | /** |
||
| 223 | * Add our custom schedule to the array of Cron schedules used by WP. |
||
| 224 | * |
||
| 225 | * @param array $schedules |
||
| 226 | * @return array |
||
| 227 | */ |
||
| 228 | public function _addCustomSchedule($schedules) { |
||
| 229 | if ( $this->checkPeriod && ($this->checkPeriod > 0) ){ |
||
| 230 | $scheduleName = 'every' . $this->checkPeriod . 'hours'; |
||
| 231 | $schedules[$scheduleName] = array( |
||
| 232 | 'interval' => $this->checkPeriod * 3600, |
||
| 233 | 'display' => sprintf('Every %d hours', $this->checkPeriod), |
||
| 234 | ); |
||
| 235 | } |
||
| 236 | return $schedules; |
||
| 237 | } |
||
| 238 | |||
| 239 | /** |
||
| 240 | * Remove the scheduled cron event that the library uses to check for updates. |
||
| 241 | * |
||
| 242 | * @return void |
||
| 243 | */ |
||
| 244 | public function removeUpdaterCron() { |
||
| 246 | } |
||
| 247 | |||
| 248 | /** |
||
| 249 | * Get the name of the update checker's WP-cron hook. Mostly useful for debugging. |
||
| 250 | * |
||
| 251 | * @return string |
||
| 252 | */ |
||
| 253 | public function getCronHookName() { |
||
| 254 | return $this->cronHook; |
||
| 255 | } |
||
| 256 | |||
| 257 | /** |
||
| 258 | * Remove most hooks added by the scheduler. |
||
| 259 | */ |
||
| 260 | public function removeHooks() { |
||
| 271 | } |
||
| 272 | } |
||
| 273 | } |
||
| 274 | } |
||
| 277 |