WordPoints_Module_Channels   A
last analyzed

Complexity

Total Complexity 6

Size/Duplication

Total Lines 70
Duplicated Lines 100 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 3
Bugs 2 Features 0
Metric Value
c 3
b 2
f 0
dl 70
loc 70
rs 10
wmc 6
lcom 1
cbo 1

5 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 10 10 2
A register() 3 3 1
A deregister() 3 3 1
A is_registered() 3 3 1
A get() 3 3 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * Module channel classes.
5
 *
6
 * @package WordPointsOrg
7
 * @since 1.0.0
8
 */
9
10
/**
11
 * Stores a list of the available module channels.
12
 *
13
 * Modules are installed and updated through various channels. This class is used to
14
 * maintain a list of the available channels.
15
 *
16
 * @since 1.0.0
17
 *
18
 * @see WordPoints_Module_Channel The object used to represent each channel.
19
 */
20 View Code Duplication
final class WordPoints_Module_Channels extends WordPoints_Container_Static {
0 ignored issues
show
Duplication introduced by
This class seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
21
22
	/**
23
	 * @since 1.0.0
24
	 */
25
	protected static $instance;
26
27
	/**
28
	 * @since 1.0.0
29
	 */
30
	protected $item_class = 'WordPoints_Module_Channel';
31
32
	/**
33
	 * Initialize the container.
34
	 *
35
	 * This function must be called before the container can be used.
36
	 *
37
	 * @since 1.0.0
38
	 *
39
	 * @return bool True if the container was initialized, false if it was already.
40
	 */
41
	public static function init() {
42
43
		if ( ! isset( self::$instance ) ) {
44
45
			self::$instance = new self;
46
			return true;
47
		}
48
49
		return false;
50
	}
51
52
	/**
53
	 * @since 1.0.0
54
	 *
55
	 * @see WordPoints_Container::_add()
56
	 */
57
	public static function register( $slug, $item, $class = null ) {
58
		return self::$instance->_add( $slug, $item, $class );
59
	}
60
61
	/**
62
	 * @since 1.0.0
63
	 *
64
	 * @see WordPoints_Container::_remove()
65
	 */
66
	public static function deregister( $slug ) {
67
		return self::$instance->_remove( $slug );
68
	}
69
70
	/**
71
	 * @since 1.0.0
72
	 *
73
	 * @see WordPoints_Container::_contains()
74
	 */
75
	public static function is_registered( $slug ) {
76
		return self::$instance->_contains( $slug );
77
	}
78
79
	/**
80
	 * @since 1.0.0
81
	 *
82
	 * @see WordPoints_Container::_get()
83
	 *
84
	 * @return WordPoints_Module_Channel[]|WordPoints_Module_Channel
85
	 */
86
	public static function get( $slug = null ) {
87
		return self::$instance->_get( $slug );
88
	}
89
}
90
WordPoints_Module_Channels::init();
91
92
/**
93
 * Module API channel class.
94
 *
95
 * A channel is similar to a channel on TV or radio. In this case, a channel is one
96
 * of many available module providers. It is a module repository, which offers
97
 * modules for download, and may also provide updates, etc.
98
 *
99
 * A channel object is usually created automatically based on the Channel header of
100
 * one of the installed modules. This file header specifies the channel URL which
101
 * should be used with that module.
102
 *
103
 * A channel is accessed through an API, which actually handles the requests to the
104
 * remote URL of this channel. This class is only intended to represent the channel
105
 * itself.
106
 *
107
 * @since 1.0.0
108
 *
109
 * @property-read WordPoints_Container_Object $modules
110
 * @property-read string                      $url
111
 */
112
final class WordPoints_Module_Channel {
113
114
	/**
115
	 * The URL of this channel.
116
	 *
117
	 * This is the channel URL, though it usually doesn't include the scheme.
118
	 *
119
	 * @since 1.0.0
120
	 *
121
	 * @var string
122
	 */
123
	private $url;
124
125
	/**
126
	 * The list of installed modules that use this channel.
127
	 *
128
	 * @since 1.0.0
129
	 *
130
	 * @var WordPoints_Container_Object
131
	 */
132
	private $modules;
133
134
	/**
135
	 * Construct the class.
136
	 *
137
	 * @since 1.0.0
138
	 *
139
	 * @param string $url The channel's URL, sans the scheme.
140
	 */
141
	public function __construct( $url ) {
142
143
		$this->url = $url;
144
		$this->modules = new WordPoints_Container_Object;
145
	}
146
147
	/**
148
	 * @since 1.0.0
149
	 */
150
	public function __get( $var ) {
151
152
		if ( 'modules' === $var || 'url' === $var ) {
153
			return $this->$var;
154
		}
155
	}
156
157
	/**
158
	 * Get the full channel URL, including the HTTP scheme.
159
	 *
160
	 * @since 1.0.0
161
	 *
162
	 * @return string The channel's full URL.
163
	 */
164
	public function get_full_url() {
165
166
		$url = 'http://' . $this->url;
167
168
		if ( $this->is_ssl_accessible() ) {
169
			$url = set_url_scheme( $url, 'https' );
170
		}
171
172
		return $url;
173
	}
174
175
	/**
176
	 * Check if this channel is accessible over SSL.
177
	 *
178
	 * @since 1.0.0
179
	 *
180
	 * @return bool Whether the channel URL can be accessed over SSL.
181
	 */
182
	public function is_ssl_accessible() {
183
184
		$transient = 'wrdpnts_' . md5( "module_channel_supports_ssl-{$this->url}" );
185
186
		$supports_ssl = get_site_transient( $transient );
187
188
		// If the transient has expired.
189
		if ( false === $supports_ssl ) {
190
191
			// The cached value is an integer so we can tell when the transient has expired.
192
			$supports_ssl = 0;
193
194
			if ( wp_http_supports( array( 'ssl' ) ) ) {
195
196
				$response = wp_safe_remote_get( 'https://' . $this->url );
197
198
				if ( ! is_wp_error( $response ) ) {
199
200
					$status = wp_remote_retrieve_response_code( $response );
201
202
					if ( 200 === (int) $status || 401 === (int) $status ) {
203
						$supports_ssl = 1;
204
					}
205
				}
206
			}
207
208
			set_site_transient( $transient, $supports_ssl, WEEK_IN_SECONDS );
209
		}
210
211
		return (bool) $supports_ssl;
212
	}
213
214
	/**
215
	 * Get the API used by this channel.
216
	 *
217
	 * @since 1.0.0
218
	 *
219
	 * @return WordPoints_Module_API|false The module API handler, or false if none available.
220
	 */
221
	public function get_api() {
222
223
		// Check if there is a cached value available.
224
		$transient = 'wrdpnts_' . md5( "module_channel_supports-{$this->url}" );
225
226
		$api = get_site_transient( $transient );
227
228
		// If the transient has expired.
229
		if ( false === $api ) {
230
231
			// Get the API specified by the remote URL.
232
			$api = $this->get_api_header();
233
234
			// Save it as a string, so we can tell when it has expired.
235
			set_site_transient( $transient, (string) $api, WEEK_IN_SECONDS );
236
		}
237
238
		return WordPoints_Module_APIs::get( $api );
239
	}
240
241
	/**
242
	 * Retrieve and parse the module API header from the remote channel.
243
	 *
244
	 * The remote channel can specify the supported API by sending the
245
	 * x-wordpoints-module-api header. This allows the API to be looked up with
246
	 * a single HEAD request.
247
	 *
248
	 * @since 1.0.0
249
	 *
250
	 * @return array|false The slug of the API specified in the header, or false
251
	 *                     the channel doesn't set this header.
252
	 */
253
	protected function get_api_header() {
254
255
		$headers = wp_get_http_headers( $this->get_full_url() );
256
257
		if ( ! isset( $headers['x-wordpoints-module-api'] ) ) {
258
			return false;
259
		}
260
261
		return sanitize_key( $headers['x-wordpoints-module-api'] );
262
	}
263
}
264
265
// EOF
266