Completed
Push — master ( e85ac8...7dbd8d )
by Der Mundschenk
03:18
created

Transients   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 152
ccs 0
cts 41
cp 0
rs 10
c 0
b 0
f 0
wmc 18

9 Methods

Rating   Name   Duplication   Size   Complexity  
A set() 0 2 2
A get() 0 2 2
A delete() 0 2 2
A set_large_object() 0 8 2
A maybe_fix_object() 0 6 2
A invalidate() 0 12 3
A get_keys_from_database() 0 17 1
A __construct() 0 4 1
A get_large_object() 0 12 3
1
<?php
2
/**
3
 * This file is part of mundschenk-at/wp-data-storage.
4
 *
5
 * Copyright 2017-2018 Peter Putzer.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or ( at your option ) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
 *
21
 * @package mundschenk-at/wp-data-storage/tests
22
 * @license http://www.gnu.org/licenses/gpl-2.0.html
23
 */
24
25
namespace Mundschenk\Data_Storage;
26
27
/**
28
 * Implements an interface to the WordPress Transients API.
29
 *
30
 * @since 1.0.0
31
 *
32
 * @author Peter Putzer <[email protected]>
33
 */
34
class Transients extends Abstract_Cache {
35
36
	const TRANSIENT_SQL_PREFIX = '_transient_';
37
	const INCREMENTOR_KEY      = 'transients_incrementor';
38
39
	/**
40
	 * Create new cache instance.
41
	 *
42
	 * @param string $prefix The prefix automatically added to transient names.
43
	 */
44
	public function __construct( $prefix ) {
45
		$this->incrementor = $this->get( $prefix . self::INCREMENTOR_KEY, true );
46
47
		parent::__construct( $prefix );
48
	}
49
50
	/**
51
	 * Invalidate all cached elements by reseting the incrementor.
52
	 */
53
	public function invalidate() {
54
55
		if ( ! \wp_using_ext_object_cache() ) {
56
			// Clean up old transients.
57
			foreach ( $this->get_keys_from_database() as $old_transient ) {
58
				$this->delete( $old_transient, true );
59
			}
60
		}
61
62
		// Update incrementor.
63
		$this->incrementor = time();
64
		$this->set( self::INCREMENTOR_KEY, $this->incrementor );
65
	}
66
67
	/**
68
	 * Retrieves a list of transients set by the plugin from the options table.
69
	 *
70
	 * @return string[]
71
	 */
72
	public function get_keys_from_database() {
73
		/**
74
		 * WordPress database handler.
75
		 *
76
		 * @var \wpdb
77
		 */
78
		global $wpdb;
79
80
		$results = $wpdb->get_results(
81
			$wpdb->prepare(
82
				"SELECT option_name FROM {$wpdb->options} WHERE option_name like %s",
83
				self::TRANSIENT_SQL_PREFIX . "{$this->get_prefix()}%"
84
			),
85
			ARRAY_A
86
		); // WPCS: db call ok, cache ok.
87
88
		return \str_replace( self::TRANSIENT_SQL_PREFIX, '', \wp_list_pluck( $results, 'option_name' ) );
89
	}
90
91
	/**
92
	 * Retrieves a cached value.
93
	 *
94
	 * @param string $key The cache key.
95
	 * @param bool   $raw Optional. Use the raw key name (i.e. don't call get_key). Default false.
96
	 *
97
	 * @return mixed
98
	 */
99
	public function get( $key, $raw = false ) {
100
		return \get_transient( $raw ? $key : $this->get_key( $key ) );
101
	}
102
103
	/**
104
	 * Retrieves a cached large object.
105
	 *
106
	 * @param string $key The cache key.
107
	 *
108
	 * @return mixed
109
	 */
110
	public function get_large_object( $key ) {
111
		$encoded = $this->get( $key );
112
		if ( false === $encoded ) {
113
			return false;
114
		}
115
116
		$uncompressed = @\gzdecode( \base64_decode( $encoded ) ); // @codingStandardsIgnoreLine
117
		if ( false === $uncompressed ) {
118
			return false;
119
		}
120
121
		return $this->maybe_fix_object( \unserialize( $uncompressed ) ); // @codingStandardsIgnoreLine
122
	}
123
124
	/**
125
	 * Sets an entry in the cache and stores the key.
126
	 *
127
	 * @param string $key       The cache key.
128
	 * @param mixed  $value     The value to store.
129
	 * @param int    $duration  Optional. The duration in seconds. Default 0 (no expiration).
130
	 * @param bool   $raw       Optional. Use the raw key name (i.e. don't call get_key). Default false.
131
	 *
132
	 * @return bool True if the cache could be set successfully.
133
	 */
134
	public function set( $key, $value, $duration = 0, $raw = false ) {
135
		return \set_transient( $raw ? $key : $this->get_key( $key ), $value, $duration );
136
	}
137
138
	/**
139
	 * Sets a transient for a large PHP object. The object will be stored in
140
	 * serialized and gzip encoded form using Base64 encoding to ensure binary safety.
141
	 *
142
	 * @param string $key       The cache key.
143
	 * @param mixed  $value     The value to store.
144
	 * @param int    $duration  Optional. The duration in seconds. Default 0 (no expiration).
145
	 *
146
	 * @return bool True if the cache could be set successfully.
147
	 */
148
	public function set_large_object( $key, $value, $duration = 0 ) {
149
		$compressed = \gzencode( \serialize( $value ) ); // @codingStandardsIgnoreLine
150
151
		if ( false === $compressed ) {
152
			return false; // @codeCoverageIgnore
153
		}
154
155
		return $this->set( $key, \base64_encode( $compressed ), $duration );
156
	}
157
158
	/**
159
	 * Deletes an entry from the cache.
160
	 *
161
	 * @param string $key The cache key root.
162
	 * @param bool   $raw Optional. Use the raw key name (i.e. don't call get_key). Default false.
163
	 *
164
	 * @return bool True on successful removal, false on failure.
165
	 */
166
	public function delete( $key, $raw = false ) {
167
		return \delete_transient( $raw ? $key : $this->get_key( $key ) );
168
	}
169
170
	/**
171
	 * Tries to fix object cache implementations sometimes returning __PHP_Incomplete_Class.
172
	 *
173
	 * Originally based on http://stackoverflow.com/a/1173769/6646342 and refactored
174
	 * for PHP 7.2 compatibility.
175
	 *
176
	 * @param  object $object An object that should have been unserialized, but may be of __PHP_Incomplete_Class.
177
	 *
178
	 * @return object         The object with its real class.
179
	 */
180
	protected function maybe_fix_object( $object ) {
181
		if ( '__PHP_Incomplete_Class' === \get_class( $object ) ) {
182
			$object = \unserialize( \serialize( $object ) ); // phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize,WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
183
		}
184
185
		return $object;
186
	}
187
}
188