Completed
Push — v1.6.0 ( 7b6d9e )
by Bradley
02:34
created

SettingBase::isJson()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
1
<?php namespace Cornford\Setter;
2
3
use Cornford\Setter\Exceptions\SettingArgumentException;
4
use DateTime;
5
use Illuminate\Database\DatabaseManager as Query;
6
use Illuminate\Config\Repository;
7
use Illuminate\Cache\Repository as Cache;
8
9
abstract class SettingBase {
10
11
	const LOCATION_DATABASE = 'database';
12
	const LOCATION_CACHE = 'cache';
13
14
	const CACHE_ENABLED = true;
15
	const CACHE_TAG = 'setter::';
16
	const CACHE_EXPIRY = true;
17
18
	/**
19
	 * Database
20
	 *
21
	 * @var \Illuminate\Database\DatabaseManager
22
	 */
23
	protected $databaseInstance;
24
25
	/**
26
	 * Config
27
	 *
28
	 * @var \Illuminate\Config\Repository
29
	 */
30
	protected $config;
31
32
	/**
33
	 * Cache
34
	 *
35
	 * @var \Illuminate\Cache\Repository
36
	 */
37
	protected $cache;
38
39
	/**
40
	 * Caching Enabled?
41
	 *
42
	 * @var boolean
43
	 */
44
	protected $cacheEnabled = true;
45
46
	/**
47
	 * Cache Tag
48
	 *
49
	 * @var string
50
	 */
51
	protected $cacheTag;
52
53
	/**
54
	 * Cache
55
	 *
56
	 * @var integer|datetime|boolean
57
	 */
58
	protected $cacheExpiry;
59
60
	/**
61
	 * Un-cached?
62
	 *
63
	 * @var boolean
64
	 */
65
	protected $uncached = false;
66
67
	/**
68
	 * Construct Setter
69
	 *
70
	 * @param Query      $database
71
	 * @param Repository $config
72
	 * @param Cache      $cache
73
	 * @param array      $options
74
	 *
75
	 * @throws SettingArgumentException
76
	 */
77
	public function __construct(Query $database, Repository $config, Cache $cache, array $options = [])
78
	{
79
		$this->database = $database;
0 ignored issues
show
Bug introduced by
The property database does not seem to exist. Did you mean databaseInstance?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
80
		$this->config = $config;
81
		$this->cache = $cache;
82
83
		if (isset($options['cache']) && !is_bool($options['cache'])) {
84
			throw new SettingArgumentException('Cache is required in boolean format.');
85
		}
86
87
		if (isset($options['tag']) && !is_string($options['tag'])) {
88
			throw new SettingArgumentException('Tag is required in string format.');
89
		}
90
91
		if (isset($options['expiry']) &&
92
			!(
93
				is_bool($options['expiry']) ||
94
				is_integer($options['expiry']) ||
95
				$options['expiry'] instanceof DateTime
96
			)
97
		) {
98
			throw new SettingArgumentException('Expiry is required in boolean, integer or DateTime format.');
99
		}
100
101
		$this->setCacheEnabled(isset($options['cache']) ? $options['cache'] : self::CACHE_ENABLED);
102
		$this->setCacheTag(isset($options['tag']) ? $options['tag'] : self::CACHE_TAG);
103
		$this->setCacheExpiry(isset($options['expiry']) ? $options['expiry'] : self::CACHE_EXPIRY);
104
	}
105
106
	/**
107
	 * Set caching enabled status.
108
	 *
109
	 * @param boolean $value
110
	 *
111
	 * @throws SettingArgumentException
112
	 *
113
	 * @return void
114
	 */
115
	protected function setCacheEnabled($value)
116
	{
117
		if (!is_bool($value)) {
118
			throw new SettingArgumentException('Cache enabled is required in boolean format.');
119
		}
120
121
		$this->cacheEnabled = $value;
122
	}
123
124
	/**
125
	 * Get the caching enabled status.
126
	 *
127
	 * @return boolean
128
	 */
129
	protected function getCacheEnabled()
130
	{
131
		return $this->cacheEnabled;
132
	}
133
134
	/**
135
	 * Cache enabled?
136
	 *
137
	 * @return boolean
138
	 */
139
	public function cacheEnabled()
140
	{
141
		return ($this->getCacheEnabled() === self::CACHE_ENABLED);
142
	}
143
144
	/**
145
	 * Set the cache tag
146
	 *
147
	 * @param string $value
148
	 *
149
	 * @throws SettingArgumentException
150
	 *
151
	 * @return void
152
	 */
153
	public function setCacheTag($value)
154
	{
155
		if (!is_string($value)) {
156
			throw new SettingArgumentException('Cache tag is required in string format.');
157
		}
158
159
		$this->cacheTag = $value;
160
	}
161
162
	/**
163
	 * Get the cache tag
164
	 *
165
	 * @return string
166
	 */
167
	public function getCacheTag()
168
	{
169
		return $this->cacheTag;
170
	}
171
172
	/**
173
	 * Set the cache expiry
174
	 *
175
	 * @param boolean|integer|DateTime $value
176
	 *
177
	 * @throws SettingArgumentException
178
	 *
179
	 * @return void
180
	 */
181 View Code Duplication
	protected function setCacheExpiry($value)
0 ignored issues
show
Duplication introduced by
This method 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...
182
	{
183
		if (!is_bool($value) && !is_integer($value) && !$value instanceof DateTime) {
184
			throw new SettingArgumentException('Expiry is required in boolean, integer or DateTime format.');
185
		}
186
187
		$this->cacheExpiry = $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like $value can also be of type object<DateTime>. However, the property $cacheExpiry is declared as type integer|object<Cornford\Setter\Datetime>|boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
188
	}
189
190
	/**
191
	 * Get the cache tag
192
	 *
193
	 * @return string
194
	 */
195
	protected function getCacheExpiry()
196
	{
197
		return $this->cacheExpiry;
198
	}
199
200
	/**
201
	 * Set the uncached status.
202
	 *
203
	 * @param boolean $value
204
	 *
205
	 * @return void
206
	 */
207
	protected function setUncached($value)
208
	{
209
		$this->uncached = $value;
210
	}
211
212
	/**
213
	 * Get the uncached status.
214
	 *
215
	 * @return boolean
216
	 */
217
	protected function getUncached()
218
	{
219
		return $this->uncached;
220
	}
221
222
	/**
223
	 * Return a key with an attached cache tag
224
	 *
225
	 * @param string $key
226
	 *
227
	 * @return string
228
	 */
229
	protected function attachCacheTag($key)
230
	{
231
		return $this->getCacheTag() . $key;
232
	}
233
234
	/**
235
	 * Check a setting exists in cache
236
	 *
237
	 * @param string $key
238
	 *
239
	 * @return boolean
240
	 */
241
	public function cacheHas($key)
242
	{
243
		return $this->cache->has($this->attachCacheTag($key)) ? true : false;
244
	}
245
246
	/**
247
	 * Forget a cached setting by key
248
	 *
249
	 * @param string $key
250
	 *
251
	 * @return boolean
252
	 */
253
	public function cacheForget($key)
254
	{
255
		$this->cache
256
			->forget($this->attachCacheTag($key));
257
258
		return true;
259
	}
260
261
	/**
262
	 * Clear all cached settings
263
	 *
264
	 * @return boolean
265
	 */
266
	public function cacheClear()
267
	{
268
		$this->cache
269
			->flush();
270
271
		return true;
272
	}
273
274
	/**
275
	 * Check a setting exists in config
276
	 *
277
	 * @param string $key
278
	 *
279
	 * @return boolean
280
	 */
281
	public function configHas($key)
282
	{
283
		return $this->config->has($key) ? true : false;
284
	}
285
286
	/**
287
	 * Arrange results into an associative array
288
	 *
289
	 * @param array  $results
290
	 * @param string $key
291
	 *
292
	 * @return array
293
	 */
294
	protected function arrangeResults($results, $key = null)
295
	{
296
		$return = array();
297
298
		foreach ($results as $path => $value) {
299
			$parts = strpos($path, '.') > 0 ? explode('.', trim(preg_replace('/^' . $key . '/', '', $path), '.')) : array($path);
300
			$target =& $return;
301
302
			foreach ($parts as $part) {
303
				$target =& $target[$part];
304
			}
305
306
			$target = $this->decodeJson($value);
307
		}
308
309
		return $return;
310
	}
311
312
	/**
313
	 * Return result values
314
	 *
315
	 * @param array  $results
316
	 * @param string $key
317
	 *
318
	 * @return string|array
319
	 */
320
	protected function returnResults($results = array(), $key)
321
	{
322
		$items = $this->arrangeResults($results, $key);
323
		$return = $this->combineResults($items, $key);
324
325
		if ((!is_array($this->returnConfig($key)) || count($this->returnConfig($key)) == 0) &&
326
			(array_key_exists($key, $return) || array_key_exists('', $return))
327
			&& count($return) == 1
328
		) {
329
			$return = reset($return);
330
		}
331
332
		if ($this->cacheEnabled()) {
333
			$this->cache->forget($this->attachCacheTag($key));
334
			$this->cache->add($this->attachCacheTag($key), $return, $this->getCacheExpiry());
335
		}
336
337
		return $this->decodeJson($return);
338
	}
339
340
	/**
341
	 * Combine result values from the database and configuration
342
	 *
343
	 * @param array  $results
344
	 * @param string $key
345
	 *
346
	 * @return array
347
	 */
348
	protected function combineResults(array $results = array(), $key)
349
	{
350
		$config = $this->returnConfig($key);
351
352
		if (is_array($config)) {
353
			return array_replace_recursive($config, $results);
354
		}
355
356
		return $results;
357
	}
358
359
	/**
360
	 * Re-cache item and its parents
361
	 *
362
	 * @param string $value
363
	 * @param string $key
364
	 *
365
	 * @return void
366
	 */
367
	protected function recacheItem($value, $key)
368
	{
369
		for ($i = 0; $i <= substr_count($key, '.') - 1; $i++) {
370
			$j = $i;
371
			$position = 0;
372
373
			while ($j >= 0) {
374
				$position =+ strpos($key, '.', $position) + 1;
375
				$j--;
376
			}
377
378
			$this->cache
379
				->forget($this->attachCacheTag(rtrim(substr_replace($key, '', $position), '.')));
380
		}
381
382
		$this->cache
383
			->forget($this->attachCacheTag($key));
384
		$this->cache
385
			->add($this->attachCacheTag($key), $value, $this->getCacheExpiry());
386
	}
387
388
	/**
389
	 * Return cache values
390
	 *
391
	 * @param string $key
392
	 *
393
	 * @return string|array
394
	 */
395
	protected function returnCache($key)
396
	{
397
		$value = $this->cache->get($this->attachCacheTag($key));
398
399
		return $this->decodeJson($value);
400
	}
401
402
	/**
403
	 * Return config values
404
	 *
405
	 * @param string $key
406
	 *
407
	 * @return string|array
408
	 */
409
	protected function returnConfig($key)
410
	{
411
		$value = $this->config->get($key);
412
413
		return $this->decodeJson($value);
414
	}
415
416
	/**
417
	 * Is the string Json encoded.
418
	 *
419
	 * @param string $string
420
	 * @return boolean
421
	 */
422
	protected function isJson($string)
423
	{
424
		if (!is_string($string)) {
425
			return false;
426
		}
427
428
		json_decode($string);
429
430
		return (json_last_error() == JSON_ERROR_NONE);
431
	}
432
433
	/**
434
	 * Decode a Json item.
435
	 *
436
	 * @param mixed $value
437
	 *
438
	 * @return mixed
439
	 */
440
	protected function decodeJson($value)
441
	{
442
		if ($this->isJson($value)) {
443
			return ($value === '""' || $value === '' ? '' : json_decode($value));
444
		}
445
446
		return $value;
447
	}
448
449
}