GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( c642a0...737b79 )
by Brad
03:35
created

FS_Storage   C

Complexity

Total Complexity 62

Size/Duplication

Total Lines 502
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 502
rs 5.9493
c 0
b 0
f 0
wmc 62
lcom 2
cbo 1

20 Methods

Rating   Name   Duplication   Size   Complexity  
A instance() 0 9 2
A __construct() 0 12 2
A set_network_active() 0 4 1
A set_site_blog_context() 0 5 1
A store() 0 8 2
B clear_all() 0 16 8
A remove() 0 8 2
A get() 0 9 2
B save() 0 12 6
A get_module_slug() 0 3 1
A get_module_type() 0 3 1
C migrate_to_network() 0 45 8
A load_network_options_map() 0 52 1
D is_multisite_option() 0 36 9
A should_use_network_storage() 0 19 4
A get_site_storage() 0 14 4
A __set() 0 7 2
A __isset() 0 5 2
A __unset() 0 7 2
A __get() 0 5 2

How to fix   Complexity   

Complex Class

Complex classes like FS_Storage 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 FS_Storage, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 22 and the first side effect is on line 10.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
    /**
3
     * @package     Freemius
4
     * @copyright   Copyright (c) 2015, Freemius, Inc.
5
     * @license     https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
     * @since       1.2.3
7
     */
8
9
    if ( ! defined( 'ABSPATH' ) ) {
10
        exit;
11
    }
12
13
    /**
14
     * Class FS_Storage
15
     *
16
     * A wrapper class for handling network level and single site level storage.
17
     *
18
     * @property bool   $is_network_activation
19
     * @property int    $network_install_blog_id
20
     * @property object $sync_cron
21
     */
22
    class FS_Storage {
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
23
        /**
24
         * @var FS_Storage[]
25
         */
26
        private static $_instances = array();
27
        /**
28
         * @var FS_Key_Value_Storage Site level storage.
29
         */
30
        private $_storage;
31
32
        /**
33
         * @var FS_Key_Value_Storage Network level storage.
34
         */
35
        private $_network_storage;
36
37
        /**
38
         * @var string
39
         */
40
        private $_module_type;
41
42
        /**
43
         * @var string
44
         */
45
        private $_module_slug;
46
47
        /**
48
         * @var int The ID of the blog that is associated with the current site level options.
49
         */
50
        private $_blog_id = 0;
51
52
        /**
53
         * @var bool
54
         */
55
        private $_is_multisite;
56
57
        /**
58
         * @var bool
59
         */
60
        private $_is_network_active = false;
61
62
        /**
63
         * @var bool
64
         */
65
        private $_is_delegated_connection = false;
66
67
        /**
68
         * @var array {
69
         * @key   string Option name.
70
         * @value int If 0 store on the network level. If 1, store on the network level only if module was network level activated. If 2, store on the network level only if network activated and NOT delegated the connection.
71
         * }
72
         */
73
        private static $_NETWORK_OPTIONS_MAP;
74
75
        /**
76
         * @author Leo Fajardo (@leorw)
77
         *
78
         * @param string $module_type
79
         * @param string $slug
80
         *
81
         * @return FS_Storage
82
         */
83
        static function instance( $module_type, $slug ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
84
            $key = $module_type . ':' . $slug;
85
86
            if ( ! isset( self::$_instances[ $key ] ) ) {
87
                self::$_instances[ $key ] = new FS_Storage( $module_type, $slug );
88
            }
89
90
            return self::$_instances[ $key ];
91
        }
92
93
        /**
94
         * @author Leo Fajardo (@leorw)
95
         *
96
         * @param string $module_type
97
         * @param string $slug
98
         */
99
        private function __construct( $module_type, $slug ) {
100
            $this->_module_type  = $module_type;
101
            $this->_module_slug  = $slug;
102
            $this->_is_multisite = is_multisite();
103
104
            if ( $this->_is_multisite ) {
105
                $this->_blog_id         = get_current_blog_id();
106
                $this->_network_storage = FS_Key_Value_Storage::instance( $module_type . '_data', $slug, true );
107
            }
108
109
            $this->_storage = FS_Key_Value_Storage::instance( $module_type . '_data', $slug, $this->_blog_id );
110
        }
111
112
        /**
113
         * Tells this storage wrapper class that the context plugin is network active. This flag will affect how values
114
         * are retrieved/stored from/into the storage.
115
         *
116
         * @author Leo Fajardo (@leorw)
117
         *
118
         * @param bool $is_network_active
119
         * @param bool $is_delegated_connection
120
         */
121
        function set_network_active( $is_network_active = true, $is_delegated_connection = false ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
122
            $this->_is_network_active       = $is_network_active;
123
            $this->_is_delegated_connection = $is_delegated_connection;
124
        }
125
126
        /**
127
         * Switch the context of the site level storage manager.
128
         *
129
         * @author Vova Feldman (@svovaf)
130
         * @since  2.0.0
131
         *
132
         * @param int $blog_id
133
         */
134
        function set_site_blog_context( $blog_id ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
135
            $this->_blog_id = $blog_id;
136
137
            $this->_storage = $this->get_site_storage( $this->_blog_id );
138
        }
139
140
        /**
141
         * @author Leo Fajardo (@leorw)
142
         *
143
         * @param string        $key
144
         * @param mixed         $value
145
         * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
146
         * @param bool          $flush
147
         */
148
        function store( $key, $value, $network_level_or_blog_id = null, $flush = true ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
149
            if ( $this->should_use_network_storage( $key, $network_level_or_blog_id ) ) {
150
                $this->_network_storage->store( $key, $value, $flush );
151
            } else {
152
                $storage = $this->get_site_storage( $network_level_or_blog_id );
0 ignored issues
show
Bug introduced by
It seems like $network_level_or_blog_id defined by parameter $network_level_or_blog_id on line 148 can also be of type boolean or null; however, FS_Storage::get_site_storage() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
153
                $storage->store( $key, $value, $flush );
154
            }
155
        }
156
157
        /**
158
         * @author Leo Fajardo (@leorw)
159
         *
160
         * @param bool          $store
161
         * @param string[]      $exceptions Set of keys to keep and not clear.
162
         * @param int|null|bool $network_level_or_blog_id
163
         */
164
        function clear_all( $store = true, $exceptions = array(), $network_level_or_blog_id = null ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
165
            if ( ! $this->_is_multisite ||
166
                 false === $network_level_or_blog_id ||
167
                 is_null( $network_level_or_blog_id ) ||
168
                 is_numeric( $network_level_or_blog_id )
169
            ) {
170
                $storage = $this->get_site_storage( $network_level_or_blog_id );
0 ignored issues
show
Bug introduced by
It seems like $network_level_or_blog_id defined by parameter $network_level_or_blog_id on line 164 can also be of type boolean or null; however, FS_Storage::get_site_storage() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
171
                $storage->clear_all( $store, $exceptions );
172
            }
173
174
            if ( $this->_is_multisite &&
175
                 ( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
176
            ) {
177
                $this->_network_storage->clear_all( $store, $exceptions );
178
            }
179
        }
180
181
        /**
182
         * @author Leo Fajardo (@leorw)
183
         *
184
         * @param string        $key
185
         * @param bool          $store
186
         * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
187
         */
188
        function remove( $key, $store = true, $network_level_or_blog_id = null ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
189
            if ( $this->should_use_network_storage( $key, $network_level_or_blog_id ) ) {
190
                $this->_network_storage->remove( $key, $store );
191
            } else {
192
                $storage = $this->get_site_storage( $network_level_or_blog_id );
0 ignored issues
show
Bug introduced by
It seems like $network_level_or_blog_id defined by parameter $network_level_or_blog_id on line 188 can also be of type boolean or null; however, FS_Storage::get_site_storage() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
193
                $storage->remove( $key, $store );
194
            }
195
        }
196
197
        /**
198
         * @author Leo Fajardo (@leorw)
199
         *
200
         * @param string        $key
201
         * @param mixed         $default
202
         * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
203
         *
204
         * @return mixed
205
         */
206
        function get( $key, $default = false, $network_level_or_blog_id = null ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
207
            if ( $this->should_use_network_storage( $key, $network_level_or_blog_id ) ) {
208
                return $this->_network_storage->get( $key, $default );
209
            } else {
210
                $storage = $this->get_site_storage( $network_level_or_blog_id );
0 ignored issues
show
Bug introduced by
It seems like $network_level_or_blog_id defined by parameter $network_level_or_blog_id on line 206 can also be of type boolean or null; however, FS_Storage::get_site_storage() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
211
212
                return $storage->get( $key, $default );
213
            }
214
        }
215
216
        /**
217
         * Multisite activated:
218
         *      true:    Save network storage.
219
         *      int:     Save site specific storage.
220
         *      false|0: Save current site storage.
221
         *      null:    Save network and current site storage.
222
         * Site level activated:
223
         *               Save site storage.
224
         *
225
         * @author Vova Feldman (@svovaf)
226
         * @since  2.0.0
227
         *
228
         * @param bool|int|null $network_level_or_blog_id
229
         */
230
        function save( $network_level_or_blog_id = null ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
231
            if ( $this->_is_network_active &&
232
                 ( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
233
            ) {
234
                $this->_network_storage->save();
235
            }
236
237
            if ( ! $this->_is_network_active || true !== $network_level_or_blog_id ) {
238
                $storage = $this->get_site_storage( $network_level_or_blog_id );
0 ignored issues
show
Bug introduced by
It seems like $network_level_or_blog_id defined by parameter $network_level_or_blog_id on line 230 can also be of type boolean or null; however, FS_Storage::get_site_storage() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
239
                $storage->save();
240
            }
241
        }
242
243
        /**
244
         * @author Vova Feldman (@svovaf)
245
         * @since  2.0.0
246
         *
247
         * @return string
248
         */
249
        function get_module_slug() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
250
            return $this->_module_slug;
251
        }
252
253
        /**
254
         * @author Vova Feldman (@svovaf)
255
         * @since  2.0.0
256
         *
257
         * @return string
258
         */
259
        function get_module_type() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
260
            return $this->_module_type;
261
        }
262
263
        /**
264
         * Migration script to the new storage data structure that is network compatible.
265
         *
266
         * IMPORTANT:
267
         *      This method should be executed only after it is determined if this is a network
268
         *      level compatible product activation.
269
         *
270
         * @author Vova Feldman (@svovaf)
271
         * @since  2.0.0
272
         */
273
        function migrate_to_network() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
274
            if ( ! $this->_is_multisite ) {
275
                return;
276
            }
277
278
            $updated = false;
279
280
            if ( ! isset( self::$_NETWORK_OPTIONS_MAP ) ) {
281
                self::load_network_options_map();
282
            }
283
284
            foreach ( self::$_NETWORK_OPTIONS_MAP as $option => $storage_level ) {
0 ignored issues
show
Bug introduced by
The expression self::$_NETWORK_OPTIONS_MAP of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
285
                if ( ! $this->is_multisite_option( $option ) ) {
286
                    continue;
287
                }
288
289
                if ( isset( $this->_storage->{$option} ) && ! isset( $this->_network_storage->{$option} ) ) {
290
                    // Migrate option to the network storage.
291
                    $this->_network_storage->store( $option, $this->_storage->{$option}, false );
292
293
                    /**
294
                     * Remove the option from site level storage.
295
                     *
296
                     * IMPORTANT:
297
                     *      The line below is intentionally commented since we want to preserve the option
298
                     *      on the site storage level for "downgrade compatibility". Basically, if the user
299
                     *      will downgrade to an older version of the plugin with the prev storage structure,
300
                     *      it will continue working.
301
                     *
302
                     * @todo After a few releases we can remove this.
303
                     */
304
//                    $this->_storage->remove($option, false);
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
305
306
                    $updated = true;
307
                }
308
            }
309
310
            if ( ! $updated ) {
311
                return;
312
            }
313
314
            // Update network level storage.
315
            $this->_network_storage->save();
316
//            $this->_storage->save();
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
317
        }
318
319
        #--------------------------------------------------------------------------------
320
        #region Helper Methods
321
        #--------------------------------------------------------------------------------
322
323
        /**
324
         * We don't want to load the map right away since it's not even needed in a non-MS environment.
325
         *
326
         * Example:
327
         * array(
328
         *      'option1' => 0, // Means that the option should always be stored on the network level.
329
         *      'option2' => 1, // Means that the option should be stored on the network level only when the module was network level activated.
330
         *      'option2' => 2, // Means that the option should be stored on the network level only when the module was network level activated AND the connection was NOT delegated.
331
         *      'option3' => 3, // Means that the option should always be stored on the site level.
332
         * )
333
         *
334
         * @author Vova Feldman (@svovaf)
335
         * @since  2.0.0
336
         */
337
        private static function load_network_options_map() {
338
            self::$_NETWORK_OPTIONS_MAP = array(
339
                // Network level options.
340
                'affiliate_application_data' => 0,
341
                'connectivity_test'          => 0,
342
                'has_trial_plan'             => 0,
343
                'install_sync_timestamp'     => 0,
344
                'install_sync_cron'          => 0,
345
                'is_anonymous_ms'            => 0,
346
                'is_on'                      => 0,
347
                'is_plugin_new_install'      => 0,
348
                'network_install_blog_id'    => 0,
349
                'pending_sites_info'         => 0,
350
                'plugin_last_version'        => 0,
351
                'plugin_main_file'           => 0,
352
                'plugin_version'             => 0,
353
                'sdk_downgrade_mode'         => 0,
354
                'sdk_last_version'           => 0,
355
                'sdk_upgrade_mode'           => 0,
356
                'sdk_version'                => 0,
357
                'sticky_optin_added_ms'      => 0,
358
                'subscriptions'              => 0,
359
                'sync_timestamp'             => 0,
360
                'sync_cron'                  => 0,
361
                'was_plugin_loaded'          => 0,
362
                'network_user_id'            => 0,
363
                'plugin_upgrade_mode'        => 0,
364
                'plugin_downgrade_mode'      => 0,
365
                'is_network_connected'       => 0,
366
                /**
367
                 * Special flag that is used when a super-admin upgrades to the new version of the SDK that
368
                 * supports network level integration, when the connection decision wasn't made for all of the
369
                 * sites in the network.
370
                 */
371
                'is_network_activation'      => 0,
372
373
                // When network activated, then network level.
374
                'install_timestamp'          => 1,
375
                'prev_is_premium'            => 1,
376
377
                // If not network activated OR delegated, then site level.
378
                'activation_timestamp'       => 2,
379
                'prev_user_id'               => 2,
380
                'sticky_optin_added'         => 2,
381
                'uninstall_reason'           => 2,
382
                'is_pending_activation'      => 2,
383
                'pending_license_key'        => 2,
384
385
                // Site level options.
386
                'is_anonymous'               => 3,
387
            );
388
        }
389
390
        /**
391
         * This method will and should only be executed when is_multisite() is true.
392
         *
393
         * @author Vova Feldman (@svovaf)
394
         * @since  2.0.0
395
         *
396
         * @param string $key
397
         *
398
         * @return bool|mixed
399
         */
400
        private function is_multisite_option( $key ) {
401
            if ( ! isset( self::$_NETWORK_OPTIONS_MAP ) ) {
402
                self::load_network_options_map();
403
            }
404
405
            if ( ! isset( self::$_NETWORK_OPTIONS_MAP[ $key ] ) ) {
406
                // Option not found -> use site level storage.
407
                return false;
408
            }
409
410
            if ( 0 === self::$_NETWORK_OPTIONS_MAP[ $key ] ) {
411
                // Option found and set to always use the network level storage on a multisite.
412
                return true;
413
            }
414
415
            if ( 3 === self::$_NETWORK_OPTIONS_MAP[ $key ] ) {
416
                // Option found and set to always use the site level storage on a multisite.
417
                return false;
418
            }
419
420
            if ( ! $this->_is_network_active ) {
421
                return false;
422
            }
423
424
            if ( 1 === self::$_NETWORK_OPTIONS_MAP[ $key ] ) {
425
                // Network activated.
426
                return true;
427
            }
428
429
            if ( 2 === self::$_NETWORK_OPTIONS_MAP[ $key ] && ! $this->_is_delegated_connection ) {
430
                // Network activated and not delegated.
431
                return true;
432
            }
433
434
            return false;
435
        }
436
437
        /**
438
         * @author Leo Fajardo
439
         *
440
         * @param string        $key
441
         * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
442
         *
443
         * @return bool
444
         */
445
        private function should_use_network_storage( $key, $network_level_or_blog_id = null ) {
446
            if ( ! $this->_is_multisite ) {
447
                // Not a multisite environment.
448
                return false;
449
            }
450
451
            if ( is_numeric( $network_level_or_blog_id ) ) {
452
                // Explicitly asked to use a specified blog storage.
453
                return false;
454
            }
455
456
            if ( is_bool( $network_level_or_blog_id ) ) {
457
                // Explicitly specified whether should use the network or blog level storage.
458
                return $network_level_or_blog_id;
459
            }
460
461
            // Determine which storage to use based on the option.
462
            return $this->is_multisite_option( $key );
463
        }
464
465
        /**
466
         * @author Vova Feldman (@svovaf)
467
         * @since  2.0.0
468
         *
469
         * @param int $blog_id
470
         *
471
         * @return \FS_Key_Value_Storage
472
         */
473
        private function get_site_storage( $blog_id = 0 ) {
474
            if ( ! is_numeric( $blog_id ) ||
475
                 $blog_id == $this->_blog_id ||
476
                 0 == $blog_id
477
            ) {
478
                return $this->_storage;
479
            }
480
481
            return FS_Key_Value_Storage::instance(
482
                $this->_module_type . '_data',
483
                $this->_storage->get_secondary_id(),
484
                $blog_id
0 ignored issues
show
Documentation introduced by
$blog_id is of type integer|double|string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
485
            );
486
        }
487
488
        #endregion
489
490
        #--------------------------------------------------------------------------------
491
        #region Magic methods
492
        #--------------------------------------------------------------------------------
493
494
        function __set( $k, $v ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
495
            if ( $this->should_use_network_storage( $k ) ) {
496
                $this->_network_storage->{$k} = $v;
497
            } else {
498
                $this->_storage->{$k} = $v;
499
            }
500
        }
501
502
        function __isset( $k ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
503
            return $this->should_use_network_storage( $k ) ?
504
                isset( $this->_network_storage->{$k} ) :
505
                isset( $this->_storage->{$k} );
506
        }
507
508
        function __unset( $k ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
509
            if ( $this->should_use_network_storage( $k ) ) {
510
                unset( $this->_network_storage->{$k} );
511
            } else {
512
                unset( $this->_storage->{$k} );
513
            }
514
        }
515
516
        function __get( $k ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
517
            return $this->should_use_network_storage( $k ) ?
518
                $this->_network_storage->{$k} :
519
                $this->_storage->{$k};
520
        }
521
522
        #endregion
523
    }