1 <?php
2
3 namespace PayPal\Common;
4
5 use PayPal\Validation\JsonValidator;
6
7 /**
8 * Generic Model class that all API domain classes extend
9 * Stores all member data in a Hashmap that enables easy
10 * JSON encoding/decoding
11 */
12 class PayPalModel
13 {
14
15 private $_propMap = array();
16
17 /**
18 * OAuth Credentials to use for this call
19 *
20 * @var \PayPal\Auth\OAuthTokenCredential $credential
21 */
22 protected static $credential;
23
24 /**
25 * Sets Credential
26 *
27 * @deprecated Pass ApiContext to create/get methods instead
28 * @param \PayPal\Auth\OAuthTokenCredential $credential
29 */
30 public static function setCredential($credential)
31 {
32 self::$credential = $credential;
33 }
34
35 /**
36 * Default Constructor
37 *
38 * You can pass data as a json representation or array object. This argument eliminates the need
39 * to do $obj->fromJson($data) later after creating the object.
40 *
41 * @param array|string|null $data
42 * @throws \InvalidArgumentException
43 */
44 public function __construct($data = null)
45 {
46 switch (gettype($data)) {
47 case "NULL":
48 break;
49 case "string":
50 JsonValidator::validate($data);
51 $this->fromJson($data);
52 break;
53 case "array":
54 $this->fromArray($data);
55 break;
56 default:
57 }
58 }
59
60 /**
61 * Returns a list of Object from Array or Json String. It is generally used when your json
62 * contains an array of this object
63 *
64 * @param mixed $data Array object or json string representation
65 * @return array
66 */
67 public static function getList($data)
68 {
69 // Return Null if Null
70 if ($data === null) {
71 return null;
72 }
73
74 if (is_a($data, get_class(new \stdClass()))) {
75 //This means, root element is object
76 return new static(json_encode($data));
77 }
78
79 $list = array();
80
81 if (is_array($data)) {
82 $data = json_encode($data);
83 }
84
85 if (JsonValidator::validate($data)) {
86 // It is valid JSON
87 $decoded = json_decode($data);
88 if ($decoded === null) {
89 return $list;
90 }
91 if (is_array($decoded)) {
92 foreach ($decoded as $k => $v) {
93 $list[] = self::getList($v);
94 }
95 }
96 if (is_a($decoded, get_class(new \stdClass()))) {
97 //This means, root element is object
98 $list[] = new static(json_encode($decoded));
99 }
100 }
101
102 return $list;
103 }
104
105 /**
106 * Magic Get Method
107 *
108 * @param $key
109 * @return mixed
110 */
111 public function __get($key)
112 {
113 if ($this->__isset($key)) {
114 return $this->_propMap[$key];
115 }
116 return null;
117 }
118
119 /**
120 * Magic Set Method
121 *
122 * @param $key
123 * @param $value
124 */
125 public function __set($key, $value)
126 {
127 if (!is_array($value) && $value === null) {
128 $this->__unset($key);
129 } else {
130 $this->_propMap[$key] = $value;
131 }
132 }
133
134 /**
135 * Converts the input key into a valid Setter Method Name
136 *
137 * @param $key
138 * @return mixed
139 */
140 private function convertToCamelCase($key)
141 {
142 return str_replace(' ', '', ucwords(str_replace(array('_', '-'), ' ', $key)));
143 }
144
145 /**
146 * Magic isSet Method
147 *
148 * @param $key
149 * @return bool
150 */
151 public function __isset($key)
152 {
153 return isset($this->_propMap[$key]);
154 }
155
156 /**
157 * Magic Unset Method
158 *
159 * @param $key
160 */
161 public function __unset($key)
162 {
163 unset($this->_propMap[$key]);
164 }
165
166 /**
167 * Converts Params to Array
168 *
169 * @param $param
170 * @return array
171 */
172 private function _convertToArray($param)
173 {
174 $ret = array();
175 foreach ($param as $k => $v) {
176 if ($v instanceof PayPalModel) {
177 $ret[$k] = $v->toArray();
178 } elseif (is_array($v) && sizeof($v) <= 0) {
179 $ret[$k] = array();
180 } elseif (is_array($v)) {
181 $ret[$k] = $this->_convertToArray($v);
182 } else {
183 $ret[$k] = $v;
184 }
185 }
186 // If the array is empty, which means an empty object,
187 // we need to convert array to StdClass object to properly
188 // represent JSON String
189 if (sizeof($ret) <= 0) {
190 $ret = new PayPalModel();
191 }
192 return $ret;
193 }
194
195 /**
196 * Fills object value from Array list
197 *
198 * @param $arr
199 * @return $this
200 */
201 public function fromArray($arr)
202 {
203 if (!empty($arr)) {
204 // Iterate over each element in array
205 foreach ($arr as $k => $v) {
206 // If the value is an array, it means, it is an object after conversion
207 if (is_array($v)) {
208 // Determine the class of the object
209 if (($clazz = ReflectionUtil::getPropertyClass(get_class($this), $k)) != null) {
210 // If the value is an associative array, it means, its an object. Just make recursive call to it.
211 if (empty($v)) {
212 if (ReflectionUtil::isPropertyClassArray(get_class($this), $k)) {
213 // It means, it is an array of objects.
214 $this->assignValue($k, array());
215 continue;
216 }
217 $o = new $clazz();
218 //$arr = array();
219 $this->assignValue($k, $o);
220 } elseif (ArrayUtil::isAssocArray($v)) {
221 /** @var self $o */
222 $o = new $clazz();
223 $o->fromArray($v);
224 $this->assignValue($k, $o);
225 } else {
226 // Else, value is an array of object/data
227 $arr = array();
228 // Iterate through each element in that array.
229 foreach ($v as $nk => $nv) {
230 if (is_array($nv)) {
231 $o = new $clazz();
232 $o->fromArray($nv);
233 $arr[$nk] = $o;
234 } else {
235 $arr[$nk] = $nv;
236 }
237 }
238 $this->assignValue($k, $arr);
239 }
240 } else {
241 $this->assignValue($k, $v);
242 }
243 } else {
244 $this->assignValue($k, $v);
245 }
246 }
247 }
248 return $this;
249 }
250
251 private function assignValue($key, $value)
252 {
253 $setter = 'set'. $this->convertToCamelCase($key);
254 // If we find the setter, use that, otherwise use magic method.
255 if (method_exists($this, $setter)) {
256 $this->$setter($value);
257 } else {
258 $this->__set($key, $value);
259 }
260 }
261
262 /**
263 * Fills object value from Json string
264 *
265 * @param $json
266 * @return $this
267 */
268 public function fromJson($json)
269 {
270 return $this->fromArray(json_decode($json, true));
271 }
272
273 /**
274 * Returns array representation of object
275 *
276 * @return array
277 */
278 public function toArray()
279 {
280 return $this->_convertToArray($this->_propMap);
281 }
282
283 /**
284 * Returns object JSON representation
285 *
286 * @param int $options http://php.net/manual/en/json.constants.php
287 * @return string
288 */
289 public function toJSON($options = 0)
290 {
291 // Because of PHP Version 5.3, we cannot use JSON_UNESCAPED_SLASHES option
292 // Instead we would use the str_replace command for now.
293 // TODO: Replace this code with return json_encode($this->toArray(), $options | 64); once we support PHP >= 5.4
294 if (version_compare(phpversion(), '5.4.0', '>=') === true) {
295 return json_encode($this->toArray(), $options | 64);
296 }
297 return str_replace('\\/', '/', json_encode($this->toArray(), $options));
298 }
299
300 /**
301 * Magic Method for toString
302 *
303 * @return string
304 */
305 public function __toString()
306 {
307 return $this->toJSON(128);
308 }
309 }
310