AbstractConfigSetting   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 281
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
wmc 27
eloc 63
c 1
b 1
f 0
dl 0
loc 281
ccs 68
cts 68
cp 1
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A _getInheritedValue() 0 7 2
A setValue() 0 25 5
A __construct() 0 15 3
A assertUsage() 0 9 4
A setWorkingCopyUrl() 0 3 1
A getName() 0 3 1
A normalizeValue() 0 3 1
A setEditor() 0 3 1
A isWithinScope() 0 3 1
A _getScopedName() 0 13 3
A getValue() 0 31 5
1
<?php
2
/**
3
 * This file is part of the SVN-Buddy library.
4
 * For the full copyright and license information, please view
5
 * the LICENSE file that was distributed with this source code.
6
 *
7
 * @copyright Alexander Obuhovich <[email protected]>
8
 * @link      https://github.com/console-helpers/svn-buddy
9
 */
10
11
namespace ConsoleHelpers\SVNBuddy\Config;
12
13
14
use ConsoleHelpers\ConsoleKit\Config\ConfigEditor;
15
16
abstract class AbstractConfigSetting
17
{
18
19
	const SCOPE_GLOBAL = 1;
20
21
	const SCOPE_WORKING_COPY = 2;
22
23
	/**
24
	 * Scope.
25
	 *
26
	 * @var integer
27
	 */
28
	private $_scope;
29
30
	/**
31
	 * Name.
32
	 *
33
	 * @var string
34
	 */
35
	private $_name;
36
37
	/**
38
	 * Default value.
39
	 *
40
	 * @var mixed
41
	 */
42
	private $_defaultValue;
43
44
	/**
45
	 * Config editor.
46
	 *
47
	 * @var ConfigEditor
48
	 */
49
	private $_editor;
50
51
	/**
52
	 * Working copy url.
53
	 *
54
	 * @var string
55
	 */
56
	private $_workingCopyUrl = '';
57
58
	/**
59
	 * Creates config setting instance.
60
	 *
61
	 * @param string  $name      Name.
62
	 * @param mixed   $default   Default value.
63
	 * @param integer $scope_bit Scope.
64
	 *
65
	 * @throws \InvalidArgumentException When wrong scope bit given.
66
	 */
67 208
	public function __construct($name, $default, $scope_bit = null)
68
	{
69 208
		if ( !isset($scope_bit) ) {
70 54
			$scope_bit = self::SCOPE_WORKING_COPY;
71
		}
72
73
		// Always add global scope.
74 208
		$this->_scope = $scope_bit | self::SCOPE_GLOBAL;
75
76 208
		if ( !in_array($scope_bit, array(self::SCOPE_WORKING_COPY, self::SCOPE_GLOBAL)) ) {
77 12
			throw new \InvalidArgumentException('The $scope must be either "working copy" or "global".');
78
		}
79
80 196
		$this->_name = $name;
81 196
		$this->_defaultValue = $this->convertToStorageFormat($this->normalizeValue($default));
82
	}
83
84
	/**
85
	 * Detects if config variable is within requested scope.
86
	 *
87
	 * @param integer $scope_bit Scope bit.
88
	 *
89
	 * @return boolean
90
	 */
91 166
	public function isWithinScope($scope_bit)
92
	{
93 166
		return ($this->_scope & $scope_bit) === $scope_bit;
94
	}
95
96
	/**
97
	 * Sets config editor.
98
	 *
99
	 * @param ConfigEditor $editor Config editor.
100
	 *
101
	 * @return void
102
	 */
103 182
	public function setEditor(ConfigEditor $editor)
104
	{
105 182
		$this->_editor = $editor;
106
	}
107
108
	/**
109
	 * Sets scope.
110
	 *
111
	 * @param string $wc_url Working copy url.
112
	 *
113
	 * @return void
114
	 */
115 38
	public function setWorkingCopyUrl($wc_url)
116
	{
117 38
		$this->_workingCopyUrl = $wc_url;
118
	}
119
120
	/**
121
	 * Returns config setting name.
122
	 *
123
	 * @return string
124
	 */
125 31
	public function getName()
126
	{
127 31
		return $this->_name;
128
	}
129
130
	/**
131
	 * Returns setting value.
132
	 *
133
	 * @param integer $scope_bit Scope bit.
134
	 *
135
	 * @return mixed
136
	 */
137 96
	public function getValue($scope_bit = null)
138
	{
139 96
		$this->assertUsage(__METHOD__, $scope_bit);
140
141 84
		if ( isset($scope_bit) ) {
142 18
			$value = $this->_editor->get(
143 18
				$this->_getScopedName(__METHOD__, $scope_bit),
144 18
				$this->_defaultValue
145 18
			);
146
		}
147
		else {
148 66
			$value = null;
149
150 66
			if ( $this->isWithinScope(self::SCOPE_WORKING_COPY) ) {
151 20
				$value = $this->_editor->get(
152 20
					$this->_getScopedName(__METHOD__, self::SCOPE_WORKING_COPY)
153 20
				);
154
			}
155
156 60
			if ( $value === null ) {
157 58
				$value = $this->_editor->get(
158 58
					$this->_getScopedName(__METHOD__, self::SCOPE_GLOBAL)
159 58
				);
160
			}
161
162 60
			if ( $value === null ) {
163 22
				$value = $this->_defaultValue;
164
			}
165
		}
166
167 78
		return $this->normalizeValue($value);
168
	}
169
170
	/**
171
	 * Changes setting value.
172
	 *
173
	 * @param mixed   $value     Value.
174
	 * @param integer $scope_bit Scope bit.
175
	 *
176
	 * @return void
177
	 */
178 107
	public function setValue($value, $scope_bit = null)
179
	{
180 107
		$this->assertUsage(__METHOD__, $scope_bit);
181
182 95
		if ( $value !== null ) {
183 95
			$value = $this->normalizeValue($value);
184 95
			$this->validate($value);
185 86
			$value = $this->convertToStorageFormat($value);
186
		}
187
188 86
		if ( !isset($scope_bit) ) {
189 74
			if ( $this->isWithinScope(self::SCOPE_WORKING_COPY) ) {
190 19
				$scope_bit = self::SCOPE_WORKING_COPY;
191
			}
192
			else {
193 55
				$scope_bit = self::SCOPE_GLOBAL;
194
			}
195
		}
196
197
		// Don't store inherited value.
198 86
		if ( $value === $this->_getInheritedValue(__METHOD__, $scope_bit) ) {
199 16
			$value = null;
200
		}
201
202 86
		$this->_editor->set($this->_getScopedName(__METHOD__, $scope_bit), $value);
203
	}
204
205
	/**
206
	 * Determines if config setting is being used correctly.
207
	 *
208
	 * @param string  $caller_method Caller method.
209
	 * @param integer $scope_bit     Scope bit.
210
	 *
211
	 * @return void
212
	 * @throws \LogicException When no editor was set upfront.
213
	 * @throws \InvalidArgumentException When $scope_bit isn't supported by config setting.
214
	 */
215 169
	public function assertUsage($caller_method, $scope_bit = null)
216
	{
217 169
		if ( !isset($this->_editor) ) {
218 12
			throw new \LogicException('Please use setEditor() before calling ' . $caller_method . '().');
219
		}
220
221 157
		if ( isset($scope_bit) && !$this->isWithinScope($scope_bit) ) {
222 12
			$error_msg = 'The usage of "%s" scope bit for "%s" config setting is forbidden.';
223 12
			throw new \InvalidArgumentException(sprintf($error_msg, $scope_bit, $this->getName()));
224
		}
225
	}
226
227
	/**
228
	 * Determines if value matches inherited one.
229
	 *
230
	 * @param string  $caller_method Caller method.
231
	 * @param integer $scope_bit     Scope bit.
232
	 *
233
	 * @return mixed
234
	 */
235 86
	private function _getInheritedValue($caller_method, $scope_bit)
236
	{
237 86
		if ( $scope_bit === self::SCOPE_WORKING_COPY ) {
238 25
			return $this->_editor->get($this->_getScopedName($caller_method, self::SCOPE_GLOBAL), $this->_defaultValue);
239
		}
240
241 61
		return $this->_defaultValue;
242
	}
243
244
	/**
245
	 * Returns scoped config setting name.
246
	 *
247
	 * @param string  $caller_method Caller method.
248
	 * @param integer $scope         Scope.
249
	 *
250
	 * @return string
251
	 * @throws \LogicException When working copy scoped name requested without working copy being set.
252
	 */
253 136
	private function _getScopedName($caller_method, $scope)
254
	{
255 136
		if ( $scope === self::SCOPE_GLOBAL ) {
256 123
			return 'global-settings.' . $this->_name;
257
		}
258
259 50
		if ( !$this->_workingCopyUrl ) {
260 12
			throw new \LogicException(
261 12
				'Please call setWorkingCopyUrl() prior to calling ' . $caller_method . '() method.'
262 12
			);
263
		}
264
265 38
		return 'path-settings[' . $this->_workingCopyUrl . '].' . $this->_name;
266
	}
267
268
	/**
269
	 * Normalizes value.
270
	 *
271
	 * @param mixed $value Value.
272
	 *
273
	 * @return mixed
274
	 */
275 56
	protected function normalizeValue($value)
276
	{
277 56
		return $value;
278
	}
279
280
	/**
281
	 * Performs value validation.
282
	 *
283
	 * @param mixed $value Value.
284
	 *
285
	 * @return void
286
	 */
287
	abstract protected function validate($value);
288
289
	/**
290
	 * Converts value into scalar for used for storage.
291
	 *
292
	 * @param mixed $value Value.
293
	 *
294
	 * @return mixed
295
	 */
296
	abstract protected function convertToStorageFormat($value);
297
298
}
299