GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

JSONStorage::onBeforeSave()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 *## JSONStorage class file
4
 *
5
 * @author: antonio ramirez <[email protected]>
6
 */
7
8
/**
9
 *## JSON Storage
10
 *
11
 * Provides a very simple way to persistent JSON storage. Acts as a registry key saver.
12
 *
13
 * Example of use:
14
 *
15
 * $j = new JSONStorage();
16
 *
17
 * $j->addRegistry('custom');
18
 * echo $j->registryExists('custom');
19
 * $j->setData('mydata','super','custom');
20
 * $j->save();
21
 * $j->load();
22
 *
23
 * echo $j->getData('super','custom');
24
 *
25
 * @package booster.components
26
 */
27
class JSONStorage extends CComponent
28
{
29
	/**
30
	 * const string the key to keep value information
31
	 */
32
	const META = 'meta';
33
34
	/**
35
	 * const string the key of the registry
36
	 */
37
	const REGISTRY = 'registry';
38
39
	/**
40
	 * @var string the filename to save the values to
41
	 */
42
	protected $filename = 'registry.json';
43
44
	/**
45
	 * @var string the full path to the directory with read/write access to save the registry to. If none set, the
46
	 * component will used the application's runtime folder
47
	 */
48
	protected $path;
49
50
	/**
51
	 * @var bool whether the registry has changed or not
52
	 */
53
	protected $dirty = false;
54
55
	/**
56
	 * @var null|string the name of the default registry
57
	 */
58
	protected $default = "default";
59
60
	/**
61
	 * @var array the data of the registry
62
	 */
63
	protected $data = array(
64
		self::META => array(
65
			"updated" => "",
66
			"hash" => ""
67
		),
68
		self::REGISTRY => array(
69
			/* collection name */
70
			"default" => array(
71
				"foo" => "bar" /* attributes by example */
72
			)
73
		)
74
	);
75
76
	/**
77
	 * class constructor
78
	 *
79
	 * @param null $registry
80
	 */
81
	public function __construct($registry = null)
82
	{
83
		if (null === $this->path) {
84
			$this->setPath(Yii::app()->getRuntimePath());
85
		} // JSON storage will be at the app runtime path
86
		$this->setFile($this->filename);
87
88
		$this->load();
89
90
		// setup domain
91
		if ($registry) {
92
			if ($this->registryExists($registry) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
93
				$this->addRegistry($registry);
94
			}
95
			$this->default = $registry;
96
		}
97
	}
98
99
	/**
100
	 * class destructor - flush data
101
	 */
102
	public function __destruct()
103
	{
104
		$this->flush();
105
	}
106
107
	/**
108
	 * Fires before registry has been saved
109
	 *
110
	 * @param CEvent $event
111
	 */
112
	public function onBeforeSave($event)
113
	{
114
		$this->raiseEvent('onBeforeSave', $event);
115
	}
116
117
	/**
118
	 * Fires after the registry has been saved
119
	 *
120
	 * @param CEvent $event
121
	 */
122
	public function onAfterSave($event)
123
	{
124
		$this->raiseEvent('onAfterSave', $event);
125
	}
126
127
	/**
128
	 * Property set path
129
	 *
130
	 * @param string $path the full path of the directory with read/write access to save the registry file to
131
	 *
132
	 * @return bool
133
	 * @throws Exception
134
	 */
135
	public function setPath($path)
136
	{
137
		if (is_dir($path) && is_writable($path)) {
138
			$this->path = substr($path, -1) == DIRECTORY_SEPARATOR ? $path : $path . DIRECTORY_SEPARATOR;
139
			return true;
140
		}
141
		throw new Exception('"Path" must be a writable directory.');
142
	}
143
144
	/**
145
	 * Property get path
146
	 * @return string
147
	 */
148
	public function getPath()
149
	{
150
		return $this->path;
151
	}
152
153
	/**
154
	 * Property set file
155
	 *
156
	 * @param string $file the filename to save the registry to
157
	 */
158
	public function setFile($file)
159
	{
160
		$this->filename = $this->path . $file;
161
	}
162
163
	/**
164
	 * Property get file
165
	 * @return string filename
166
	 */
167
	public function getFile()
168
	{
169
		return $this->filename;
170
	}
171
172
	/**
173
	 * Verifies data integrity
174
	 * @return bool
175
	 */
176
	public function verify()
177
	{
178
		$registry = function_exists('json_encode')
179
			? json_encode($this->data[self::REGISTRY])
180
			: CJSON::encode(
181
				$this->data[self::REGISTRY]
182
			);
183
		return $this->data[self::META]["hash"] == md5($registry);
184
	}
185
186
	/**
187
	 * Loads registry data into memory
188
	 * @throws Exception
189
	 */
190
	public function load()
191
	{
192
		$filename = $this->getFile();
193
		if (!file_exists($filename))
194
			return;
195
196
		$json = file_get_contents($filename);
197
		if (strlen($json) == 0)
198
			return;
199
200
		$data = $this->decode($json);
201
		if ($data === null)
202
			throw new Exception('Error while trying to decode ' . $filename . '.');
203
204
		$this->data = $data;
0 ignored issues
show
Documentation Bug introduced by
It seems like $data of type * is incompatible with the declared type array of property $data.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
205
206
		if (!$this->verify())
207
			throw new Exception($filename . ' failed checksum validation.');
208
	}
209
210
	/**
211
	 * Saves registry data to the file
212
	 */
213
	public function save()
214
	{
215
		if ($this->hasEventHandler('onBeforeSave')) {
216
			$this->onBeforeSave(new CEvent($this));
217
		}
218
		$this->flush();
219
		if ($this->hasEventHandler('onAfterSave')) {
220
			$this->onAfterSave(new CEvent($this));
221
		}
222
	}
223
224
	/**
225
	 * Saves data to the registry
226
	 *
227
	 * @param string $key the name of the key that will hold the data
228
	 * @param array $data the data to save
229
	 * @param string $registry the name of the registry
230
	 *
231
	 * @return bool
232
	 */
233
	public function setData($key, $data, $registry = null)
234
	{
235
		if ($registry == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $registry of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
236
			$registry = $this->default;
237
		}
238
		if (is_string($key . $registry) && $this->registryExists($registry)) {
239
			$this->data[self::REGISTRY][$registry][$key] = $data;
240
			$this->dirty = true;
241
			return true;
242
		}
243
		return false;
244
	}
245
246
	/**
247
	 * Retrieves a data value from the registry
248
	 *
249
	 * @param string $key the name of the key that holds the data
250
	 * @param string $registry the registry name
251
	 *
252
	 * @return mixed the data in the key value, null otherwise
253
	 */
254
	public function getData($key, $registry = null)
255
	{
256
		if ($registry == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $registry of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
257
			$registry = $this->default;
258
		}
259
		if (is_string($key . $registry) && $this->registryExists($registry)) {
260
			if (array_key_exists($key, $this->data[self::REGISTRY][$registry])) {
261
				return $this->data[self::REGISTRY][$registry][$key];
262
			}
263
		}
264
		return null;
265
	}
266
267
	/**
268
	 * Removes data from a key in the registry
269
	 *
270
	 * @param string $key the key name that holds the data to remove
271
	 * @param string $registry the registry name
272
	 *
273
	 * @return bool true if successful, false otherwise
274
	 */
275
	public function removeData($key, $registry = null)
276
	{
277
		if ($registry == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $registry of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
278
			$registry = $this->default;
279
		}
280
281
		if (is_string($key . $registry) && $this->registryExists($registry)) {
282
			if (array_key_exists($key, $this->data[self::REGISTRY][$registry])) {
283
				unset($this->data[self::REGISTRY][$registry][$key]);
284
				$this->dirty = true;
285
				return true;
286
			}
287
		}
288
		return false;
289
	}
290
291
	/**
292
	 * Retrieves the number of keys in registry
293
	 *
294
	 * @param string $registry the registry name
295
	 *
296
	 * @return int the data length
297
	 */
298
	public function getLength($registry = null)
299
	{
300
		if ($registry == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $registry of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
301
			$registry = $this->default;
302
		}
303
		if (is_string($registry) && $this->registryExists($registry)) {
304
			return count($this->data[self::REGISTRY][$registry]);
305
		}
306
		return 0;
307
	}
308
309
	/**
310
	 * Retrieves a registry collection based on its name
311
	 *
312
	 * @param string $registry the name of the registry to retrieve
313
	 *
314
	 * @return mixed|null the registry, null if none found
315
	 */
316
	public function getRegistry($registry)
317
	{
318
		return $this->registryExists($registry) ? $this->data[self::REGISTRY][$registry] : null;
319
	}
320
321
	/**
322
	 * Checkes whether a collection exists (registry)
323
	 *
324
	 * @param string $registry the name of the registry to check existence
325
	 *
326
	 * @return bool
327
	 */
328
	public function registryExists($registry)
329
	{
330
		return array_key_exists($registry, $this->data[self::REGISTRY]);
331
	}
332
333
	/**
334
	 * Add new collection name
335
	 *
336
	 * @param string $registry the name of the registry (collection) to create
337
	 *
338
	 * @return bool
339
	 */
340
	public function addRegistry($registry)
341
	{
342
		if ($this->registryExists($registry)) {
343
			return false;
344
		}
345
		$this->data[self::REGISTRY][$registry] = array();
346
		$this->dirty = true;
347
		return true;
348
	}
349
350
	/**
351
	 * Remove an existing collection and all associated data
352
	 *
353
	 * @param string $registry the name of the registry to remove
354
	 *
355
	 * @return bool
356
	 */
357
	public function removeRegistry($registry)
358
	{
359
		if ($this->registryExists($registry)) {
360
			unset($this->data[self::REGISTRY][$registry]);
361
			$this->dirty = true;
362
			return true;
363
		}
364
		return false;
365
	}
366
367
	/**
368
	 * Saves the global registry to the file
369
	 * @return bool
370
	 * @throws Exception
371
	 */
372
	private function flush()
373
	{
374
		// check if writeback is needed
375
		if ($this->dirty == false)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
376
			return true;
377
378
		// prepare to writeback to file
379
		$data = $this->data;
380
		$registry = $this->encode($this->data[self::REGISTRY]);
381
		$data[self::META]["updated"] = date("c");
382
		$data[self::META]["hash"] = md5($registry);
383
384
		// overwrite existing data
385
		$written = file_put_contents($this->getFile(), $this->encode($data));
386
		if ($written === false)
387
			throw new Exception(strtr( 'Unable to write back to {FILE}. Data will be lost!', array('{FILE}' => $this->getFile()) ));
388
389
		return true;
390
	}
391
392
	/**
393
	 * JSON encodes the data
394
	 *
395
	 * @param mixed $data
396
	 *
397
	 * @return string
398
	 */
399
	private function encode($data)
400
	{
401
		return function_exists('json_encode') ? json_encode($data) : CJSON::encode($data);
402
	}
403
404
	/**
405
	 * JSON decodes the data
406
	 *
407
	 * @param string $data
408
	 *
409
	 * @return mixed
410
	 */
411
	private function decode($data)
412
	{
413
		return function_exists('json_decode') ? json_decode($data, true) : CJSON::decode($data, true);
414
	}
415
}
416