PluginProbe
Tiered Pricing Table for WooCommerce / 2.3.2
Tiered Pricing Table for WooCommerce v2.3.2
7.1.7 7.1.5 7.1.4 7.1.1 6.5.0 6.4.0 6.1.0 trunk 1.0 1.1 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.2.0 2.2.1 2.2.2 2.2.3 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 All 90 releases
tier-pricing-table / freemius / includes / managers / class-fs-option-manager.php

class-fs-option-manager.php in Tiered Pricing Table for WooCommerce 2.3.2, at freemius/includes/managers/class-fs-option-manager.php

498 lines 15.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
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.0.3
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * 3-layer lazy options manager.
15 * layer 3: Memory
16 * layer 2: Cache (if there's any caching plugin and if WP_FS__DEBUG_SDK is FALSE)
17 * layer 1: Database (options table). All options stored as one option record in the DB to reduce number of DB
18 * queries.
19 *
20 * If load() is not explicitly called, starts as empty manager. Same thing about saving the data - you have to
21 * explicitly call store().
22 *
23 * Class Freemius_Option_Manager
24 */
25 class FS_Option_Manager {
26 /**
27 * @var string
28 */
29 private $_id;
30 /**
31 * @var array|object
32 */
33 private $_options;
34 /**
35 * @var FS_Logger
36 */
37 private $_logger;
38
39 /**
40 * @since 2.0.0
41 * @var int The ID of the blog that is associated with the current site level options.
42 */
43 private $_blog_id = 0;
44
45 /**
46 * @since 2.0.0
47 * @var bool
48 */
49 private $_is_network_storage;
50
51 /**
52 * @var array[string]FS_Option_Manager {
53 * @key string
54 * @value FS_Option_Manager
55 * }
56 */
57 private static $_MANAGERS = array();
58
59 /**
60 * @author Vova Feldman (@svovaf)
61 * @since 1.0.3
62 *
63 * @param string $id
64 * @param bool $load
65 * @param bool|int $network_level_or_blog_id Since 2.0.0
66 */
67 private function __construct( $id, $load = false, $network_level_or_blog_id = false ) {
68 $id = strtolower( $id );
69
70 $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_opt_mngr_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
71
72 $this->_logger->entrance();
73 $this->_logger->log( 'id = ' . $id );
74
75 $this->_id = $id;
76
77 if ( is_multisite() ) {
78 $this->_is_network_storage = ( true === $network_level_or_blog_id );
79
80 if ( is_numeric( $network_level_or_blog_id ) ) {
81 $this->_blog_id = $network_level_or_blog_id;
82 }
83 } else {
84 $this->_is_network_storage = false;
85 }
86
87 if ( $load ) {
88 $this->load();
89 }
90 }
91
92 /**
93 * @author Vova Feldman (@svovaf)
94 * @since 1.0.3
95 *
96 * @param string $id
97 * @param bool $load
98 * @param bool|int $network_level_or_blog_id Since 2.0.0
99 *
100 * @return FS_Option_Manager
101 */
102 static function get_manager( $id, $load = false, $network_level_or_blog_id = false ) {
103 $key = strtolower( $id );
104
105 if ( is_multisite() ) {
106 if ( true === $network_level_or_blog_id ) {
107 $key .= ':ms';
108 } else if ( is_numeric( $network_level_or_blog_id ) && $network_level_or_blog_id > 0 ) {
109 $key .= ":{$network_level_or_blog_id}";
110 } else {
111 $network_level_or_blog_id = get_current_blog_id();
112
113 $key .= ":{$network_level_or_blog_id}";
114 }
115 }
116
117 if ( ! isset( self::$_MANAGERS[ $key ] ) ) {
118 self::$_MANAGERS[ $key ] = new FS_Option_Manager( $id, $load, $network_level_or_blog_id );
119 } // If load required but not yet loaded, load.
120 else if ( $load && ! self::$_MANAGERS[ $key ]->is_loaded() ) {
121 self::$_MANAGERS[ $key ]->load();
122 }
123
124 return self::$_MANAGERS[ $key ];
125 }
126
127 /**
128 * @author Vova Feldman (@svovaf)
129 * @since 1.0.3
130 *
131 * @param bool $flush
132 */
133 function load( $flush = false ) {
134 $this->_logger->entrance();
135
136 $option_name = $this->get_option_manager_name();
137
138 if ( $flush || ! isset( $this->_options ) ) {
139 if ( isset( $this->_options ) ) {
140 // Clear prev options.
141 $this->clear();
142 }
143
144 $cache_group = $this->get_cache_group();
145
146 if ( WP_FS__DEBUG_SDK ) {
147
148 // Don't use cache layer in DEBUG mode.
149 $load_options = empty( $this->_options );
150
151 } else {
152
153 $this->_options = wp_cache_get(
154 $option_name,
155 $cache_group
156 );
157
158 $load_options = ( false === $this->_options );
159 }
160
161 $cached = true;
162
163 if ( $load_options ) {
164 if ( $this->_is_network_storage ) {
165 $this->_options = get_site_option( $option_name );
166 } else if ( $this->_blog_id > 0 ) {
167 $this->_options = get_blog_option( $this->_blog_id, $option_name );
168 } else {
169 $this->_options = get_option( $option_name );
170 }
171
172 if ( is_string( $this->_options ) ) {
173 $this->_options = json_decode( $this->_options );
174 }
175
176 // $this->_logger->info('get_option = ' . var_export($this->_options, true));
177
178 if ( false === $this->_options ) {
179 $this->clear();
180 }
181
182 $cached = false;
183 }
184
185 if ( ! WP_FS__DEBUG_SDK && ! $cached ) {
186 // Set non encoded cache.
187 wp_cache_set( $option_name, $this->_options, $cache_group );
188 }
189 }
190 }
191
192 /**
193 * @author Vova Feldman (@svovaf)
194 * @since 1.0.3
195 *
196 * @return bool
197 */
198 function is_loaded() {
199 return isset( $this->_options );
200 }
201
202 /**
203 * @author Vova Feldman (@svovaf)
204 * @since 1.0.3
205 *
206 * @return bool
207 */
208 function is_empty() {
209 return ( $this->is_loaded() && false === $this->_options );
210 }
211
212 /**
213 * @author Vova Feldman (@svovaf)
214 * @since 1.0.6
215 *
216 * @param bool $flush
217 */
218 function clear( $flush = false ) {
219 $this->_logger->entrance();
220
221 $this->_options = array();
222
223 if ( $flush ) {
224 $this->store();
225 }
226 }
227
228 /**
229 * Delete options manager from DB.
230 *
231 * @author Vova Feldman (@svovaf)
232 * @since 1.0.9
233 */
234 function delete() {
235 $option_name = $this->get_option_manager_name();
236
237 if ( $this->_is_network_storage ) {
238 delete_site_option( $option_name );
239 } else if ( $this->_blog_id > 0 ) {
240 delete_blog_option( $this->_blog_id, $option_name );
241 } else {
242 delete_option( $option_name );
243 }
244 }
245
246 /**
247 * @author Vova Feldman (@svovaf)
248 * @since 1.0.6
249 *
250 * @param string $option
251 *
252 * @return bool
253 */
254 function has_option( $option ) {
255 return array_key_exists( $option, $this->_options );
256 }
257
258 /**
259 * @author Vova Feldman (@svovaf)
260 * @since 1.0.3
261 *
262 * @param string $option
263 * @param mixed $default
264 *
265 * @return mixed
266 */
267 function get_option( $option, $default = null ) {
268 $this->_logger->entrance( 'option = ' . $option );
269
270 if ( ! $this->is_loaded() ) {
271 $this->load();
272 }
273
274 if ( is_array( $this->_options ) ) {
275 $value = isset( $this->_options[ $option ] ) ?
276 $this->_options[ $option ] :
277 $default;
278 } else if ( is_object( $this->_options ) ) {
279 $value = isset( $this->_options->{$option} ) ?
280 $this->_options->{$option} :
281 $default;
282 } else {
283 $value = $default;
284 }
285
286 /**
287 * If it's an object, return a clone of the object, otherwise,
288 * external changes of the object will actually change the value
289 * of the object in the options manager which may lead to an unexpected
290 * behaviour and data integrity when a store() call is triggered.
291 *
292 * Example:
293 * $object1 = $options->get_option( 'object1' );
294 * $object1->x = 123;
295 *
296 * $object2 = $options->get_option( 'object2' );
297 * $object2->y = 'dummy';
298 *
299 * $options->set_option( 'object2', $object2, true );
300 *
301 * If we don't return a clone of option 'object1', setting 'object2'
302 * will also store the updated value of 'object1' which is quite not
303 * an expected behaviour.
304 *
305 * @author Vova Feldman
306 */
307 return is_object( $value ) ? clone $value : $value;
308 }
309
310 /**
311 * @author Vova Feldman (@svovaf)
312 * @since 1.0.3
313 *
314 * @param string $option
315 * @param mixed $value
316 * @param bool $flush
317 */
318 function set_option( $option, $value, $flush = false ) {
319 $this->_logger->entrance( 'option = ' . $option );
320
321 if ( ! $this->is_loaded() ) {
322 $this->clear();
323 }
324
325 /**
326 * If it's an object, store a clone of the object, otherwise,
327 * external changes of the object will actually change the value
328 * of the object in the options manager which may lead to an unexpected
329 * behaviour and data integrity when a store() call is triggered.
330 *
331 * Example:
332 * $object1 = new stdClass();
333 * $object1->x = 123;
334 *
335 * $options->set_option( 'object1', $object1 );
336 *
337 * $object1->x = 456;
338 *
339 * $options->set_option( 'object2', $object2, true );
340 *
341 * If we don't set the option as a clone of option 'object1', setting 'object2'
342 * will also store the updated value of 'object1' ($object1->x = 456 instead of
343 * $object1->x = 123) which is quite not an expected behaviour.
344 *
345 * @author Vova Feldman
346 */
347 $copy = is_object( $value ) ? clone $value : $value;
348
349 if ( is_array( $this->_options ) ) {
350 $this->_options[ $option ] = $copy;
351 } else if ( is_object( $this->_options ) ) {
352 $this->_options->{$option} = $copy;
353 }
354
355 if ( $flush ) {
356 $this->store();
357 }
358 }
359
360 /**
361 * Unset option.
362 *
363 * @author Vova Feldman (@svovaf)
364 * @since 1.0.3
365 *
366 * @param string $option
367 * @param bool $flush
368 */
369 function unset_option( $option, $flush = false ) {
370 $this->_logger->entrance( 'option = ' . $option );
371
372 if ( is_array( $this->_options ) ) {
373 if ( ! isset( $this->_options[ $option ] ) ) {
374 return;
375 }
376
377 unset( $this->_options[ $option ] );
378
379 } else if ( is_object( $this->_options ) ) {
380 if ( ! isset( $this->_options->{$option} ) ) {
381 return;
382 }
383
384 unset( $this->_options->{$option} );
385 }
386
387 if ( $flush ) {
388 $this->store();
389 }
390 }
391
392 /**
393 * Dump options to database.
394 *
395 * @author Vova Feldman (@svovaf)
396 * @since 1.0.3
397 */
398 function store() {
399 $this->_logger->entrance();
400
401 $option_name = $this->get_option_manager_name();
402
403 if ( $this->_logger->is_on() ) {
404 $this->_logger->info( $option_name . ' = ' . var_export( $this->_options, true ) );
405 }
406
407 // Update DB.
408 if ( $this->_is_network_storage ) {
409 update_site_option( $option_name, $this->_options );
410 } else if ( $this->_blog_id > 0 ) {
411 update_blog_option( $this->_blog_id, $option_name, $this->_options );
412 } else {
413 update_option( $option_name, $this->_options );
414 }
415
416 if ( ! WP_FS__DEBUG_SDK ) {
417 wp_cache_set( $option_name, $this->_options, $this->get_cache_group() );
418 }
419 }
420
421 /**
422 * Get options keys.
423 *
424 * @author Vova Feldman (@svovaf)
425 * @since 1.0.3
426 *
427 * @return string[]
428 */
429 function get_options_keys() {
430 if ( is_array( $this->_options ) ) {
431 return array_keys( $this->_options );
432 } else if ( is_object( $this->_options ) ) {
433 return array_keys( get_object_vars( $this->_options ) );
434 }
435
436 return array();
437 }
438
439 #--------------------------------------------------------------------------------
440 #region Migration
441 #--------------------------------------------------------------------------------
442
443 /**
444 * Migrate options from site level.
445 *
446 * @author Vova Feldman (@svovaf)
447 * @since 2.0.0
448 */
449 function migrate_to_network() {
450 $site_options = FS_Option_Manager::get_manager($this->_id, true, false);
451
452 $options = is_object( $site_options->_options ) ?
453 get_object_vars( $site_options->_options ) :
454 $site_options->_options;
455
456 if ( ! empty( $options ) ) {
457 foreach ( $options as $key => $val ) {
458 $this->set_option( $key, $val, false );
459 }
460
461 $this->store();
462 }
463 }
464
465 #endregion
466
467 #--------------------------------------------------------------------------------
468 #region Helper Methods
469 #--------------------------------------------------------------------------------
470
471 /**
472 * @return string
473 */
474 private function get_option_manager_name() {
475 return $this->_id;
476 }
477
478 /**
479 * @author Vova Feldman (@svovaf)
480 * @since 2.0.0
481 *
482 * @return string
483 */
484 private function get_cache_group() {
485 $group = WP_FS__SLUG;
486
487 if ( $this->_is_network_storage ) {
488 $group .= '_ms';
489 } else if ( $this->_blog_id > 0 ) {
490 $group .= "_s{$this->_blog_id}";
491 }
492
493 return $group;
494 }
495
496 #endregion
497 }
498