1<?php
2
3namespace DDDBL;
4
5/**
6  * a DataObject is a generic object
7  * to store data under given keys.
8  *
9  * it allows getting, adding, updating and deleting
10  * data.
11  *
12  * a validation callback can be provided
13  * to ensure, that the stored data
14  * validate correctly.
15  *
16  **/
17class DataObject {
18
19  /**
20    * list of stored data
21    **/
22  private $arrData = array();
23
24  /**
25    * callback to validate all stored data
26    **/
27  private $cloValidator = null;
28
29  /**
30    * @param $cloValidator - optional validator callback to validate stored data
31    * @param $arrData      - optional list of data to store in object
32    *
33    * @throws UnexpectedParameterTypeException - if validator callback is not a callable
34    *
35    * initiates the data-object and stores the validator callback. if no
36    * callback is given, a default callback is stored, which validates against
37    * everything.
38    *
39    * if optional data are given, they are passed to DataObject::add(), to be stored
40    * immediatley
41    *
42    **/
43  public function __construct($cloValidator = null, array $arrData = array()) {
44
45    if(!is_null($cloValidator) && !is_callable($cloValidator))
46      throw new UnexpectedParameterTypeException('callable', $cloValidator);
47
48    $this->cloValidator = (!is_null($cloValidator)) ? $cloValidator : function() {return true; };
49
50    if(!empty($arrData))
51      $this->add($arrData);
52
53  }
54
55  /**
56    * @param $arrData - list of data to store in object
57    *
58    * @throws \Exception - if a key is already in use
59    * @throws \Exception - if the final data-set do not validate
60    *
61    * add the list of data to the existing ones. the given data
62    * must have the following format:
63    * array([key] => data
64    *       [key] => data, [..])
65    *
66    * if a key in the given data is already used in stored
67    * data the addition is aborted and an exception is
68    * thrown.
69    *
70    * the stored data are only modified on success
71    *
72    **/
73  public function add(array $arrData) {
74
75    $arrMergedData = array_merge($this->arrData, $arrData);
76
77    foreach($arrData AS $strKey => $mixData)
78      if(array_key_exists($strKey, $this->arrData))
79        throw new \Exception("could not store data, key is already in use: $strKey");
80
81    $cloValidator = $this->cloValidator;
82
83    if(!$cloValidator($arrMergedData))
84      throw new \Exception("given data do not validate");
85
86    $this->arrData = $arrMergedData;
87
88  }
89
90  /**
91    * @param $arrData - list of data to update
92    *
93    * @throws \Exception - if the final data-set do not validate
94    *
95    * update the stored data with the given data-set. for
96    * the structure of $arrData have a look at DataObject:add()
97    *
98    * existing keys are overwritten with new values. new
99    * keys are added to the data-set.
100    *
101    * if validation of final set fails, an exception is
102    * thrown. no data are modified on failure.
103    *
104    **/
105  public function update(array $arrData) {
106
107    $arrMergedData = array_merge($this->arrData, $arrData);
108
109    $cloValidator = $this->cloValidator;
110
111    if(!$cloValidator($arrMergedData))
112      throw new \Exception("given data do not validate");
113
114    $this->arrData = $arrMergedData;
115
116  }
117
118  /**
119    * @param $strKey - the key of the value to delete
120    *
121    * @throws UnexpectedParameterTypeException - if given key is not a string
122    *
123    * delete the value stored under the given key.
124    * if given key do not exists, nothing is done!
125    *
126    **/
127  public function delete($strKey) {
128
129    if(!is_string($strKey))
130      throw new UnexpectedParameterTypeException('string', $strKey);
131
132    if($this->exists($strKey))
133      unset($this->arrData[$strKey]);
134
135  }
136
137  /**
138    * @param $strKey - the key to check
139    *
140    * @throws UnexpectedParameterTypeException - if given key is not a string
141    *
142    * @return (boolean) true, if key exists
143    * @return (boolean) false, if key do not exists
144    *
145    * check if the given key exists
146    *
147    **/
148  public function exists($strKey) {
149
150    if(!is_string($strKey))
151      throw new UnexpectedParameterTypeException('string', $strKey);
152
153    if(!array_key_exists($strKey, $this->arrData))
154      return false;
155
156    return true;
157
158  }
159
160  /**
161    * @param $strKey - the key to get the value from
162    *
163    * @throws UnexpectedParameterTypeException - if given key is not a string
164    * @throws \Exception - if given key is unknown
165    *
166    * @return (mixed) the value stored under the given key
167    *
168    * return the value stored under the given key
169    *
170    **/
171  public function get($strKey) {
172
173    if(!is_string($strKey))
174      throw new UnexpectedParameterTypeException('string', $strKey);
175
176    if(!$this->exists($strKey))
177      throw new \Exception("unknown key: $strKey");
178
179    return $this->arrData[$strKey];
180
181  }
182
183  /**
184    * return all stored data in the structure of:
185    * array([key] => data
186    *       [key] => data, [..])
187    *
188    **/
189  public function getAll() {
190
191    return $this->arrData;
192
193  }
194
195}