HCE Project DC service web UI  0.2
Hierarchical Cluster Engine DC service web UI
 All Classes Namespaces Files Functions Variables Pages
JSONStorage.php
Go to the documentation of this file.
1 <?php
27 class JSONStorage extends CComponent
28 {
32  const META = 'meta';
33 
37  const REGISTRY = 'registry';
38 
42  protected $filename = 'registry.json';
43 
48  protected $path;
49 
53  protected $dirty = false;
54 
58  protected $default = "default";
59 
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 
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) {
93  $this->addRegistry($registry);
94  }
95  $this->default = $registry;
96  }
97  }
98 
102  public function __destruct()
103  {
104  $this->flush();
105  }
106 
112  public function onBeforeSave($event)
113  {
114  $this->raiseEvent('onBeforeSave', $event);
115  }
116 
122  public function onAfterSave($event)
123  {
124  $this->raiseEvent('onAfterSave', $event);
125  }
126 
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 
148  public function getPath()
149  {
150  return $this->path;
151  }
152 
158  public function setFile($file)
159  {
160  $this->filename = $this->path . $file;
161  }
162 
167  public function getFile()
168  {
169  return $this->filename;
170  }
171 
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 
190  public function load()
191  {
192  // load data
193  if (file_exists($this->getFile())) {
194  $json = file_get_contents($this->getFile());
195  if (strlen($json) == 0) {
196  return;
197  }
198 
199  $this->data = $this->decode($json);
200 
201  if ($this->data === null) {
202  throw new Exception('Error while trying to decode ' . $this->getFile() . '.');
203  }
204 
205  if (!$this->verify()) {
206  throw new Exception($this->getFile() . ' failed checksum validation.');
207  }
208  }
209  }
210 
214  public function save()
215  {
216  if ($this->hasEventHandler('onBeforeSave')) {
217  $this->onBeforeSave(new CEvent($this));
218  }
219  $this->flush();
220  if ($this->hasEventHandler('onAfterSave')) {
221  $this->onAfterSave(new CEvent($this));
222  }
223  }
224 
234  public function setData($key, $data, $registry = null)
235  {
236  if ($registry == null) {
237  $registry = $this->default;
238  }
239  if (is_string($key . $registry) && $this->registryExists($registry)) {
240  $this->data[self::REGISTRY][$registry][$key] = $data;
241  $this->dirty = true;
242  return true;
243  }
244  return false;
245  }
246 
255  public function getData($key, $registry = null)
256  {
257  if ($registry == null) {
258  $registry = $this->default;
259  }
260  if (is_string($key . $registry) && $this->registryExists($registry)) {
261  if (array_key_exists($key, $this->data[self::REGISTRY][$registry])) {
262  return $this->data[self::REGISTRY][$registry][$key];
263  }
264  }
265  return null;
266  }
267 
276  public function removeData($key, $registry = null)
277  {
278  if ($registry == null) {
279  $registry = $this->default;
280  }
281 
282  if (is_string($key . $registry) && $this->registryExists($registry)) {
283  if (array_key_exists($key, $this->data[self::REGISTRY][$registry])) {
284  unset($this->data[self::REGISTRY][$registry][$key]);
285  $this->dirty = true;
286  return true;
287  }
288  }
289  return false;
290  }
291 
299  public function getLength($registry = null)
300  {
301  if ($registry == null) {
302  $registry = $this->default;
303  }
304  if (is_string($registry) && $this->registryExists($registry)) {
305  return count($this->data[self::REGISTRY][$registry]);
306  }
307  return 0;
308  }
309 
317  public function getRegistry($registry)
318  {
319  return $this->registryExists($registry) ? $this->data[self::REGISTRY][$registry] : null;
320  }
321 
329  public function registryExists($registry)
330  {
331  return array_key_exists($registry, $this->data[self::REGISTRY]);
332  }
333 
341  public function addRegistry($registry)
342  {
343  if ($this->registryExists($registry)) {
344  return false;
345  }
346  $this->data[self::REGISTRY][$registry] = array();
347  $this->dirty = true;
348  return true;
349  }
350 
358  public function removeRegistry($registry)
359  {
360  if ($this->registryExists($registry)) {
361  unset($this->data[self::REGISTRY][$registry]);
362  $this->dirty = true;
363  return true;
364  }
365  return false;
366  }
367 
373  private function flush()
374  {
375  // check if writeback is needed
376  if ($this->dirty == false) {
377  return true;
378  }
379  // prepare to writeback to file
380  $data = $this->data;
381  $registry = $this->encode($this->data[self::REGISTRY]);
382  $data[self::META]["updated"] = date("c");
383  $data[self::META]["hash"] = md5($registry);
384 
385  // overwrite existing data
386  if (file_put_contents($this->getFile(), $this->encode($data))) {
387  return true;
388  } else {
389  throw new Exception(strtr(
390  'Unable to write back to {FILE}. Data will be lost!',
391  array('{FILE}' => $this->getFile())
392  ));
393  }
394  }
395 
403  private function encode($data)
404  {
405  return function_exists('json_encode') ? json_encode($data) : CJSON::encode($data);
406  }
407 
415  private function decode($data)
416  {
417  return function_exists('json_decode') ? json_decode($data, true) : CJSON::decode($data, true);
418  }
419 }