Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.50% covered (warning)
87.50%
14 / 16
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
PCG_Rollout
93.33% covered (success)
93.33%
14 / 15
75.00% covered (warning)
75.00%
3 / 4
8.02
0.00% covered (danger)
0.00%
0 / 1
 init
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 gate
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 is_enabled_for_blog
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
4.02
 blog_bucket
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Percentage-based rollout gate for the Plugin Conflicts Guardian.
4 *
5 * @package automattic/jetpack-mu-wpcom
6 */
7
8/**
9 * Percentage rollout gate for PCG.
10 */
11class PCG_Rollout {
12
13    const DEFAULT_PERCENTAGE = 20;
14
15    /**
16     * Priority 100 leaves room for emergency overrides at higher priorities.
17     */
18    public static function init() {
19        add_filter( 'pcg_guard_activation', array( __CLASS__, 'gate' ), 100 );
20        add_filter( 'pcg_guard_updates', array( __CLASS__, 'gate' ), 100 );
21    }
22
23    /**
24     * Only narrows.
25     *
26     * @param bool $enabled Previous filter value.
27     * @return bool
28     */
29    public static function gate( $enabled ) {
30        if ( ! $enabled ) {
31            return $enabled;
32        }
33        return self::is_enabled_for_blog( get_current_blog_id() );
34    }
35
36    /**
37     * On single-site, `get_current_blog_id()` is always 1, so the site is
38     * wholly in or wholly out at any given percentage.
39     *
40     * @param int $blog_id Blog ID under test.
41     * @return bool
42     */
43    public static function is_enabled_for_blog( $blog_id ) {
44        $blog_id = (int) $blog_id;
45        if ( $blog_id <= 0 ) {
46            return false;
47        }
48
49        $percentage = (int) apply_filters( 'pcg_rollout_percentage', self::DEFAULT_PERCENTAGE );
50        if ( $percentage <= 0 ) {
51            return false;
52        }
53        if ( $percentage >= 100 ) {
54            return true;
55        }
56
57        return self::blog_bucket( $blog_id ) < $percentage;
58    }
59
60    /**
61     * `abs()` on the modulo result (not raw `crc32`) — 32-bit PHP returns
62     * a signed int and `abs(PHP_INT_MIN)` overflows.
63     *
64     * @internal Exposed for tests.
65     * @param int $blog_id Blog ID.
66     * @return int
67     */
68    public static function blog_bucket( $blog_id ) {
69        return abs( crc32( (string) (int) $blog_id ) % 100 );
70    }
71}
72
73PCG_Rollout::init();