PluginProbe ʕ •ᴥ•ʔ
Atarim – Visual Feedback, Review & AI Collaboration / 3.22
Atarim – Visual Feedback, Review & AI Collaboration v3.22
trunk 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 3.2.0 3.2.1 3.22 3.22.1 3.22.2 3.22.3 3.22.4 3.22.5 3.22.6 3.3.0 3.3.1 3.3.2 3.3.2.1 3.3.2.2 3.3.3 3.30 3.31 3.32 3.4 3.4.1 3.4.3 3.4.4 3.5 3.5.1 3.6 3.6.1 3.7 3.8 3.9 3.9.1 3.9.2 3.9.3 3.9.4 3.9.6 3.9.6.1 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.2 4.2.1 4.2.2 4.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.4
atarim-visual-collaboration / src / Model.php
atarim-visual-collaboration / src Last commit date
AccessToken 2 years ago AuthHandler 2 years ago Http 2 years ago Service 2 years ago Task 2 years ago Utils 2 years ago Client.php 2 years ago Collection.php 2 years ago Exception.php 2 years ago Model.php 2 years ago Service.php 2 years ago aliases.php 2 years ago
Model.php
333 lines
1 <?php
2 /*
3 * Copyright 2011 Google Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 namespace Google;
19
20 use Google\Exception as GoogleException;
21 use ReflectionObject;
22 use ReflectionProperty;
23 use stdClass;
24
25 /**
26 * This class defines attributes, valid values, and usage which is generated
27 * from a given json schema.
28 * http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5
29 *
30 */
31 class Model implements \ArrayAccess
32 {
33 /**
34 * If you need to specify a NULL JSON value, use Google\Model::NULL_VALUE
35 * instead - it will be replaced when converting to JSON with a real null.
36 */
37 const NULL_VALUE = "{}gapi-php-null";
38 protected $internal_gapi_mappings = [];
39 protected $modelData = [];
40 protected $processed = [];
41
42 /**
43 * Polymorphic - accepts a variable number of arguments dependent
44 * on the type of the model subclass.
45 */
46 final public function __construct()
47 {
48 if (func_num_args() == 1 && is_array(func_get_arg(0))) {
49 // Initialize the model with the array's contents.
50 $array = func_get_arg(0);
51 $this->mapTypes($array);
52 }
53 $this->gapiInit();
54 }
55
56 /**
57 * Getter that handles passthrough access to the data array, and lazy object creation.
58 * @param string $key Property name.
59 * @return mixed The value if any, or null.
60 */
61 public function __get($key)
62 {
63 $keyType = $this->keyType($key);
64 $keyDataType = $this->dataType($key);
65 if ($keyType && !isset($this->processed[$key])) {
66 if (isset($this->modelData[$key])) {
67 $val = $this->modelData[$key];
68 } elseif ($keyDataType == 'array' || $keyDataType == 'map') {
69 $val = [];
70 } else {
71 $val = null;
72 }
73
74 if ($this->isAssociativeArray($val)) {
75 if ($keyDataType && 'map' == $keyDataType) {
76 foreach ($val as $arrayKey => $arrayItem) {
77 $this->modelData[$key][$arrayKey] =
78 new $keyType($arrayItem);
79 }
80 } else {
81 $this->modelData[$key] = new $keyType($val);
82 }
83 } elseif (is_array($val)) {
84 $arrayObject = [];
85 foreach ($val as $arrayIndex => $arrayItem) {
86 $arrayObject[$arrayIndex] = new $keyType($arrayItem);
87 }
88 $this->modelData[$key] = $arrayObject;
89 }
90 $this->processed[$key] = true;
91 }
92
93 return isset($this->modelData[$key]) ? $this->modelData[$key] : null;
94 }
95
96 /**
97 * Initialize this object's properties from an array.
98 *
99 * @param array $array Used to seed this object's properties.
100 * @return void
101 */
102 protected function mapTypes($array)
103 {
104 // Hard initialise simple types, lazy load more complex ones.
105 foreach ($array as $key => $val) {
106 if ($keyType = $this->keyType($key)) {
107 $dataType = $this->dataType($key);
108 if ($dataType == 'array' || $dataType == 'map') {
109 $this->$key = [];
110 foreach ($val as $itemKey => $itemVal) {
111 if ($itemVal instanceof $keyType) {
112 $this->{$key}[$itemKey] = $itemVal;
113 } else {
114 $this->{$key}[$itemKey] = new $keyType($itemVal);
115 }
116 }
117 } elseif ($val instanceof $keyType) {
118 $this->$key = $val;
119 } else {
120 $this->$key = new $keyType($val);
121 }
122 unset($array[$key]);
123 } elseif (property_exists($this, $key)) {
124 $this->$key = $val;
125 unset($array[$key]);
126 } elseif (property_exists($this, $camelKey = $this->camelCase($key))) {
127 // This checks if property exists as camelCase, leaving it in array as snake_case
128 // in case of backwards compatibility issues.
129 $this->$camelKey = $val;
130 }
131 }
132 $this->modelData = $array;
133 }
134
135 /**
136 * Blank initialiser to be used in subclasses to do post-construction initialisation - this
137 * avoids the need for subclasses to have to implement the variadics handling in their
138 * constructors.
139 */
140 protected function gapiInit()
141 {
142 return;
143 }
144
145 /**
146 * Create a simplified object suitable for straightforward
147 * conversion to JSON. This is relatively expensive
148 * due to the usage of reflection, but shouldn't be called
149 * a whole lot, and is the most straightforward way to filter.
150 */
151 public function toSimpleObject()
152 {
153 $object = new stdClass();
154
155 // Process all other data.
156 foreach ($this->modelData as $key => $val) {
157 $result = $this->getSimpleValue($val);
158 if ($result !== null) {
159 $object->$key = $this->nullPlaceholderCheck($result);
160 }
161 }
162
163 // Process all public properties.
164 $reflect = new ReflectionObject($this);
165 $props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);
166 foreach ($props as $member) {
167 $name = $member->getName();
168 $result = $this->getSimpleValue($this->$name);
169 if ($result !== null) {
170 $name = $this->getMappedName($name);
171 $object->$name = $this->nullPlaceholderCheck($result);
172 }
173 }
174
175 return $object;
176 }
177
178 /**
179 * Handle different types of values, primarily
180 * other objects and map and array data types.
181 */
182 private function getSimpleValue($value)
183 {
184 if ($value instanceof Model) {
185 return $value->toSimpleObject();
186 } elseif (is_array($value)) {
187 $return = [];
188 foreach ($value as $key => $a_value) {
189 $a_value = $this->getSimpleValue($a_value);
190 if ($a_value !== null) {
191 $key = $this->getMappedName($key);
192 $return[$key] = $this->nullPlaceholderCheck($a_value);
193 }
194 }
195 return $return;
196 }
197 return $value;
198 }
199
200 /**
201 * Check whether the value is the null placeholder and return true null.
202 */
203 private function nullPlaceholderCheck($value)
204 {
205 if ($value === self::NULL_VALUE) {
206 return null;
207 }
208 return $value;
209 }
210
211 /**
212 * If there is an internal name mapping, use that.
213 */
214 private function getMappedName($key)
215 {
216 if (isset($this->internal_gapi_mappings, $this->internal_gapi_mappings[$key])) {
217 $key = $this->internal_gapi_mappings[$key];
218 }
219 return $key;
220 }
221
222 /**
223 * Returns true only if the array is associative.
224 * @param array $array
225 * @return bool True if the array is associative.
226 */
227 protected function isAssociativeArray($array)
228 {
229 if (!is_array($array)) {
230 return false;
231 }
232 $keys = array_keys($array);
233 foreach ($keys as $key) {
234 if (is_string($key)) {
235 return true;
236 }
237 }
238 return false;
239 }
240
241 /**
242 * Verify if $obj is an array.
243 * @throws \Google\Exception Thrown if $obj isn't an array.
244 * @param array $obj Items that should be validated.
245 * @param string $method Method expecting an array as an argument.
246 */
247 public function assertIsArray($obj, $method)
248 {
249 if ($obj && !is_array($obj)) {
250 throw new GoogleException(
251 "Incorrect parameter type passed to $method(). Expected an array."
252 );
253 }
254 }
255
256 /** @return bool */
257 #[\ReturnTypeWillChange]
258 public function offsetExists($offset)
259 {
260 return isset($this->$offset) || isset($this->modelData[$offset]);
261 }
262
263 /** @return mixed */
264 #[\ReturnTypeWillChange]
265 public function offsetGet($offset)
266 {
267 return isset($this->$offset) ?
268 $this->$offset :
269 $this->__get($offset);
270 }
271
272 /** @return void */
273 #[\ReturnTypeWillChange]
274 public function offsetSet($offset, $value)
275 {
276 if (property_exists($this, $offset)) {
277 $this->$offset = $value;
278 } else {
279 $this->modelData[$offset] = $value;
280 $this->processed[$offset] = true;
281 }
282 }
283
284 /** @return void */
285 #[\ReturnTypeWillChange]
286 public function offsetUnset($offset)
287 {
288 unset($this->modelData[$offset]);
289 }
290
291 protected function keyType($key)
292 {
293 $keyType = $key . "Type";
294
295 // ensure keyType is a valid class
296 if (property_exists($this, $keyType) && class_exists($this->$keyType)) {
297 return $this->$keyType;
298 }
299 }
300
301 protected function dataType($key)
302 {
303 $dataType = $key . "DataType";
304
305 if (property_exists($this, $dataType)) {
306 return $this->$dataType;
307 }
308 }
309
310 public function __isset($key)
311 {
312 return isset($this->modelData[$key]);
313 }
314
315 public function __unset($key)
316 {
317 unset($this->modelData[$key]);
318 }
319
320 /**
321 * Convert a string to camelCase
322 * @param string $value
323 * @return string
324 */
325 private function camelCase($value)
326 {
327 $value = ucwords(str_replace(['-', '_'], ' ', $value));
328 $value = str_replace(' ', '', $value);
329 $value[0] = strtolower($value[0]);
330 return $value;
331 }
332 }
333