Completed
Push — master ( d2ebbd...d83ef4 )
by David
03:02
created

Wordlift_File_Cache_Service::has_cache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Services: File Cache Service
4
 *
5
 * The File Cache Service provides on-disk caching.
6
 *
7
 * @since      3.16.0
8
 * @package    Wordlift
9
 * @subpackage Wordlift/includes/cache
10
 */
11
12
/**
13
 * Define the {@link Wordlift_File_Cache_Service} class.
14
 *
15
 * @since 3.16.0
16
 */
17
class Wordlift_File_Cache_Service implements Wordlift_Cache_Service {
18
19
	/**
20
	 * The cache directory.
21
	 *
22
	 * @since  3.16.0
23
	 * @access private
24
	 * @var string $cache_dir The root cache directory (ending with a trailing slash).
25
	 */
26
	private $cache_dir;
27
28
	/**
29
	 * The file extension for cache files (e.g. `.wlcache`).
30
	 *
31
	 * @since  3.16.0
32
	 * @access private
33
	 * @var string $file_extension The file extension for cache files (e.g. `.wlcache`).
34
	 */
35
	private $file_extension;
36
37
	/**
38
	 * A {@link Wordlift_Log_Service} instance.
39
	 *
40
	 * @since  3.16.0
41
	 * @access private
42
	 * @var \Wordlift_Log_Service $log A {@link Wordlift_Log_Service} instance.
43
	 */
44
	private $log;
45
46
	/**
47
	 * The {@link Wordlift_File_Cache_Service} registered instances.
48
	 *
49
	 * Each {@link Wordlift_File_Cache_Service} adds itself to the registered
50
	 * instances.
51
	 *
52
	 * @since  3.16.3
53
	 * @access private
54
	 * @var array $instances An array of {@link Wordlift_File_Cache_Service} instances.
55
	 */
56
	private static $instances = array();
57
58
	/**
59
	 * Create a {@link Wordlift_File_Cache_Service} instance.
60
	 *
61
	 * The File Cache Service requires a base cache directory (to which a unique
62
	 * id for the current site will be appended) and a file extension for cache
63
	 * files (by default `.wlcache`) is used.
64
	 *
65
	 * @since 3.16.0
66
	 *
67
	 * @param string $cache_dir      The base cache directory.
68
	 * @param string $file_extension The file extension, by default `.wlcache`.
69
	 */
70
	public function __construct( $cache_dir, $file_extension = '.wlcache' ) {
71
72
		$this->log = Wordlift_Log_Service::get_logger( get_class() );
73
74
		// Set the cache directory using the base directory provided by the caller
75
		// and appending a hash for the unique site id.
76
		$this->cache_dir      = trailingslashit( $cache_dir ) . md5( get_site_url() ) . '/';
77
		$this->file_extension = $file_extension;
78
79
		// Create the cache dir.
80
		if ( ! file_exists( $this->cache_dir ) ) {
81
			mkdir( $this->cache_dir, 0755, true );
82
		}
83
84
		// Add ourselves to the list of instances.
85
		self::$instances[] = $this;
86
87
		$this->log->debug( "File Cache service initialized on $this->cache_dir." );
88
89
	}
90
91
	/**
92
	 * @inheritdoc
93
	 */
94
	function get_cache( $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...
95
96
		// Bail out if we don't have the cache.
97
		if ( ! $this->has_cache( $id ) ) {
98
			return false;
99
		}
100
101
		// Get the filename.
102
		$filename = $this->get_filename( $id );
103
104
		$this->log->trace( "Trying to get cache contents for $id from $filename..." );
105
106
		// Try to decode the contents.
107
		$contents = json_decode( file_get_contents( $filename ), true );
108
109
		// Return false if decoding failed, otherwise the decoded contents.
110
		return $contents ?: false;
111
	}
112
113
	/**
114
	 * @inheritdoc
115
	 */
116
	function has_cache( $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...
117
118
		// Get the filename.
119
		$filename = $this->get_filename( $id );
120
121
		// Bail out if the file doesn't exist.
122
		return file_exists( $filename );
123
	}
124
125
	/**
126
	 * @inheritdoc
127
	 */
128
	function set_cache( $id, $contents ) {
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...
129
130
		$filename = $this->get_filename( $id );
131
132
		$this->log->trace( "Writing cache contents for $id to $filename..." );
133
134
		file_put_contents( $filename, wp_json_encode( $contents ) );
135
136
	}
137
138
	/**
139
	 * @inheritdoc
140
	 */
141
	function delete_cache( $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...
142
143
		$filename = $this->get_filename( $id );
144
145
		$this->log->trace( "Deleting cache contents for $id, file $filename..." );
146
147
		wp_delete_file( $filename );
148
149
	}
150
151
	/**
152
	 * @inheritdoc
153
	 */
154
	function flush() {
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...
155
156
		// Bail out if the cache dir isn't set.
157
		if ( empty( $this->cache_dir ) || '/' === $this->cache_dir ) {
158
			return;
159
		}
160
161
		$this->log->trace( "Flushing cache contents from $this->cache_dir..." );
162
163
		$handle = @opendir( $this->cache_dir );
164
165
		// Bail out if the directory can't be opened.
166
		if ( false === $handle ) {
167
			return;
168
		}
169
170
		// Calculate the file extension length for matching file names.
171
		$file_extension_length = strlen( $this->file_extension );
172
173
		// Loop into the directory to delete files.
174
		while ( false !== ( $entry = readdir( $handle ) ) ) {
175
			if ( $this->file_extension === substr( $entry, - $file_extension_length ) ) {
176
				$this->log->trace( "Deleting file {$this->cache_dir}{$entry}..." );
177
				wp_delete_file( $this->cache_dir . $entry );
178
			}
179
		}
180
181
		// Finally closed the directory.
182
		closedir( $handle );
183
184
	}
185
186
	public static function flush_all() {
187
188
		foreach ( self::$instances as $instance ) {
189
			$instance->flush();
190
		}
191
192
	}
193
194
	/**
195
	 * Get the filename holding the cache contents for the specified `id`.
196
	 *
197
	 * @since 3.16.0
198
	 *
199
	 * @param int $id The cache `id`.
200
	 *
201
	 * @return string The filename.
202
	 */
203
	private function get_filename( $id ) {
204
205
		return $this->cache_dir . md5( $id ) . $this->file_extension;
206
	}
207
208
}
209