Completed
Push — master ( 330c1d...2983ac )
by Der Mundschenk
02:48
created

Transients::get()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 2
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
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
38
	/**
39
	 * The incrementor transient key.
40
	 *
41
	 * @var string
42
	 */
43
	private $incrementor_key;
44
45
	/**
46
	 * Create new cache instance.
47
	 *
48
	 * @param string $prefix The prefix automatically added to transient names.
49
	 */
50 1
	public function __construct( $prefix ) {
51 1
		$this->incrementor_key = "{$prefix}transients_incrementor";
52 1
		$this->incrementor     = \get_transient( $this->incrementor_key );
53
54 1
		parent::__construct( $prefix );
55 1
	}
56
57
	/**
58
	 * Invalidate all cached elements by reseting the incrementor.
59
	 */
60 2
	public function invalidate() {
61
62 2
		if ( ! \wp_using_ext_object_cache() ) {
63
			// Clean up old transients.
64 1
			foreach ( $this->get_keys_from_database() as $old_transient ) {
65 1
				\delete_transient( $old_transient );
66
			}
67
		}
68
69
		// Update incrementor.
70 2
		$this->incrementor = time();
71 2
		\set_transient( $this->incrementor_key, $this->incrementor );
72 2
	}
73
74
	/**
75
	 * Retrieves a list of transients set by the plugin from the options table.
76
	 *
77
	 * @return string[]
78
	 */
79 1
	public function get_keys_from_database() {
80
		/**
81
		 * WordPress database handler.
82
		 *
83
		 * @var \wpdb
84
		 */
85 1
		global $wpdb;
86
87 1
		$results = $wpdb->get_results(
88 1
			$wpdb->prepare(
89 1
				"SELECT option_name FROM {$wpdb->options} WHERE option_name like %s",
90 1
				self::TRANSIENT_SQL_PREFIX . "{$this->get_prefix()}%"
91
			),
92 1
			ARRAY_A
93
		); // WPCS: db call ok, cache ok.
94
95 1
		return \str_replace( self::TRANSIENT_SQL_PREFIX, '', \wp_list_pluck( $results, 'option_name' ) );
96
	}
97
98
	/**
99
	 * Retrieves a cached value.
100
	 *
101
	 * @param string $key The cache key.
102
	 *
103
	 * @return mixed
104
	 */
105 1
	public function get( $key ) {
106 1
		return \get_transient( $this->get_key( $key ) );
107
	}
108
109
	/**
110
	 * Retrieves a cached large object.
111
	 *
112
	 * @param string $key The cache key.
113
	 *
114
	 * @return mixed
115
	 */
116 3
	public function get_large_object( $key ) {
117 3
		$encoded = $this->get( $key );
118 3
		if ( false === $encoded ) {
119 1
			return false;
120
		}
121
122 2
		$uncompressed = @\gzdecode( \base64_decode( $encoded ) ); // @codingStandardsIgnoreLine
123 2
		if ( false === $uncompressed ) {
0 ignored issues
show
introduced by
The condition false === $uncompressed is always false.
Loading history...
124 1
			return false;
125
		}
126
127 1
		return $this->maybe_fix_object( \unserialize( $uncompressed ) ); // @codingStandardsIgnoreLine
128
	}
129
130
	/**
131
	 * Sets an entry in the cache and stores the key.
132
	 *
133
	 * @param string $key       The cache key.
134
	 * @param mixed  $value     The value to store.
135
	 * @param int    $duration  Optional. The duration in seconds. Default 0 (no expiration).
136
	 *
137
	 * @return bool True if the cache could be set successfully.
138
	 */
139 1
	public function set( $key, $value, $duration = 0 ) {
140 1
		return \set_transient( $this->get_key( $key ), $value, $duration );
141
	}
142
143
	/**
144
	 * Sets a transient for a large PHP object. The object will be stored in
145
	 * serialized and gzip encoded form using Base64 encoding to ensure binary safety.
146
	 *
147
	 * @param string $key       The cache key.
148
	 * @param mixed  $value     The value to store.
149
	 * @param int    $duration  Optional. The duration in seconds. Default 0 (no expiration).
150
	 *
151
	 * @return bool True if the cache could be set successfully.
152
	 */
153 1
	public function set_large_object( $key, $value, $duration = 0 ) {
154 1
		$compressed = \gzencode( \serialize( $value ) ); // @codingStandardsIgnoreLine
155
156 1
		if ( false === $compressed ) {
157
			return false; // @codeCoverageIgnore
158
		}
159
160 1
		return $this->set( $key, \base64_encode( $compressed ), $duration );
161
	}
162
163
	/**
164
	 * Deletes an entry from the cache.
165
	 *
166
	 * @param string $key The cache key root.
167
	 *
168
	 * @return bool True on successful removal, false on failure.
169
	 */
170 1
	public function delete( $key ) {
171 1
		return \delete_transient( $this->get_key( $key ) );
172
	}
173
174
	/**
175
	 * Tries to fix object cache implementations sometimes returning __PHP_Incomplete_Class.
176
	 *
177
	 * Originally based on http://stackoverflow.com/a/1173769/6646342 and refactored
178
	 * for PHP 7.2 compatibility.
179
	 *
180
	 * @param  object $object An object that should have been unserialized, but may be of __PHP_Incomplete_Class.
181
	 *
182
	 * @return object         The object with its real class.
183
	 */
184 1
	protected function maybe_fix_object( $object ) {
185 1
		if ( '__PHP_Incomplete_Class' === \get_class( $object ) ) {
186 1
			$object = \unserialize( \serialize( $object ) ); // phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize,WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
187
		}
188
189 1
		return $object;
190
	}
191
}
192