source: vendor/google/apiclient/src/Model.php@ e3d4e0a

Last change on this file since e3d4e0a was e3d4e0a, checked in by Vlado 222039 <vlado.popovski@…>, 7 days ago

Upload project files

  • Property mode set to 100644
File size: 10.0 KB
RevLine 
[e3d4e0a]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
18namespace Google;
19
20use Google\Exception as GoogleException;
21use ReflectionObject;
22use ReflectionProperty;
23use 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#[\AllowDynamicProperties]
32class Model implements \ArrayAccess
33{
34 /**
35 * If you need to specify a NULL JSON value, use Google\Model::NULL_VALUE
36 * instead - it will be replaced when converting to JSON with a real null.
37 */
38 const NULL_VALUE = "{}gapi-php-null";
39 protected $internal_gapi_mappings = [];
40 protected $modelData = [];
41 protected $processed = [];
42
43 /**
44 * Polymorphic - accepts a variable number of arguments dependent
45 * on the type of the model subclass.
46 */
47 final public function __construct()
48 {
49 if (func_num_args() == 1 && is_array(func_get_arg(0))) {
50 // Initialize the model with the array's contents.
51 $array = func_get_arg(0);
52 $this->mapTypes($array);
53 }
54 $this->gapiInit();
55 }
56
57 /**
58 * Getter that handles passthrough access to the data array, and lazy object creation.
59 * @param string $key Property name.
60 * @return mixed The value if any, or null.
61 */
62 public function __get($key)
63 {
64 $keyType = $this->keyType($key);
65 $keyDataType = $this->dataType($key);
66 if ($keyType && !isset($this->processed[$key])) {
67 if (isset($this->modelData[$key])) {
68 $val = $this->modelData[$key];
69 } elseif ($keyDataType == 'array' || $keyDataType == 'map') {
70 $val = [];
71 } else {
72 $val = null;
73 }
74
75 if ($this->isAssociativeArray($val)) {
76 if ($keyDataType && 'map' == $keyDataType) {
77 foreach ($val as $arrayKey => $arrayItem) {
78 $this->modelData[$key][$arrayKey] =
79 new $keyType($arrayItem);
80 }
81 } else {
82 $this->modelData[$key] = new $keyType($val);
83 }
84 } elseif (is_array($val)) {
85 $arrayObject = [];
86 foreach ($val as $arrayIndex => $arrayItem) {
87 $arrayObject[$arrayIndex] = new $keyType($arrayItem);
88 }
89 $this->modelData[$key] = $arrayObject;
90 }
91 $this->processed[$key] = true;
92 }
93
94 return isset($this->modelData[$key]) ? $this->modelData[$key] : null;
95 }
96
97 /**
98 * Initialize this object's properties from an array.
99 *
100 * @param array $array Used to seed this object's properties.
101 * @return void
102 */
103 protected function mapTypes($array)
104 {
105 // Hard initialise simple types, lazy load more complex ones.
106 foreach ($array as $key => $val) {
107 if ($keyType = $this->keyType($key)) {
108 $dataType = $this->dataType($key);
109 if ($dataType == 'array' || $dataType == 'map') {
110 $this->$key = [];
111 foreach ($val as $itemKey => $itemVal) {
112 if ($itemVal instanceof $keyType) {
113 $this->{$key}[$itemKey] = $itemVal;
114 } else {
115 $this->{$key}[$itemKey] = new $keyType($itemVal);
116 }
117 }
118 } elseif ($val instanceof $keyType) {
119 $this->$key = $val;
120 } else {
121 $this->$key = new $keyType($val);
122 }
123 unset($array[$key]);
124 } elseif (property_exists($this, $key)) {
125 $this->$key = $val;
126 unset($array[$key]);
127 } elseif (property_exists($this, $camelKey = $this->camelCase($key))) {
128 // This checks if property exists as camelCase, leaving it in array as snake_case
129 // in case of backwards compatibility issues.
130 $this->$camelKey = $val;
131 }
132 }
133 $this->modelData = $array;
134 }
135
136 /**
137 * Blank initialiser to be used in subclasses to do post-construction initialisation - this
138 * avoids the need for subclasses to have to implement the variadics handling in their
139 * constructors.
140 */
141 protected function gapiInit()
142 {
143 return;
144 }
145
146 /**
147 * Create a simplified object suitable for straightforward
148 * conversion to JSON. This is relatively expensive
149 * due to the usage of reflection, but shouldn't be called
150 * a whole lot, and is the most straightforward way to filter.
151 */
152 public function toSimpleObject()
153 {
154 $object = new stdClass();
155
156 // Process all other data.
157 foreach ($this->modelData as $key => $val) {
158 $result = $this->getSimpleValue($val);
159 if ($result !== null) {
160 $object->$key = $this->nullPlaceholderCheck($result);
161 }
162 }
163
164 // Process all public properties.
165 $reflect = new ReflectionObject($this);
166 $props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);
167 foreach ($props as $member) {
168 $name = $member->getName();
169 $result = $this->getSimpleValue($this->$name);
170 if ($result !== null) {
171 $name = $this->getMappedName($name);
172 $object->$name = $this->nullPlaceholderCheck($result);
173 }
174 }
175
176 return $object;
177 }
178
179 /**
180 * Handle different types of values, primarily
181 * other objects and map and array data types.
182 */
183 private function getSimpleValue($value)
184 {
185 if ($value instanceof Model) {
186 return $value->toSimpleObject();
187 } elseif (is_array($value)) {
188 $return = [];
189 foreach ($value as $key => $a_value) {
190 $a_value = $this->getSimpleValue($a_value);
191 if ($a_value !== null) {
192 $key = $this->getMappedName($key);
193 $return[$key] = $this->nullPlaceholderCheck($a_value);
194 }
195 }
196 return $return;
197 }
198 return $value;
199 }
200
201 /**
202 * Check whether the value is the null placeholder and return true null.
203 */
204 private function nullPlaceholderCheck($value)
205 {
206 if ($value === self::NULL_VALUE) {
207 return null;
208 }
209 return $value;
210 }
211
212 /**
213 * If there is an internal name mapping, use that.
214 */
215 private function getMappedName($key)
216 {
217 if (isset($this->internal_gapi_mappings, $this->internal_gapi_mappings[$key])) {
218 $key = $this->internal_gapi_mappings[$key];
219 }
220 return $key;
221 }
222
223 /**
224 * Returns true only if the array is associative.
225 * @param array $array
226 * @return bool True if the array is associative.
227 */
228 protected function isAssociativeArray($array)
229 {
230 if (!is_array($array)) {
231 return false;
232 }
233 $keys = array_keys($array);
234 foreach ($keys as $key) {
235 if (is_string($key)) {
236 return true;
237 }
238 }
239 return false;
240 }
241
242 /**
243 * Verify if $obj is an array.
244 * @throws \Google\Exception Thrown if $obj isn't an array.
245 * @param array $obj Items that should be validated.
246 * @param string $method Method expecting an array as an argument.
247 */
248 public function assertIsArray($obj, $method)
249 {
250 if ($obj && !is_array($obj)) {
251 throw new GoogleException(
252 "Incorrect parameter type passed to $method(). Expected an array."
253 );
254 }
255 }
256
257 /** @return bool */
258 #[\ReturnTypeWillChange]
259 public function offsetExists($offset)
260 {
261 return isset($this->$offset) || isset($this->modelData[$offset]);
262 }
263
264 /** @return mixed */
265 #[\ReturnTypeWillChange]
266 public function offsetGet($offset)
267 {
268 return isset($this->$offset) ?
269 $this->$offset :
270 $this->__get($offset);
271 }
272
273 /** @return void */
274 #[\ReturnTypeWillChange]
275 public function offsetSet($offset, $value)
276 {
277 if (property_exists($this, $offset)) {
278 $this->$offset = $value;
279 } else {
280 $this->modelData[$offset] = $value;
281 $this->processed[$offset] = true;
282 }
283 }
284
285 /** @return void */
286 #[\ReturnTypeWillChange]
287 public function offsetUnset($offset)
288 {
289 unset($this->modelData[$offset]);
290 }
291
292 protected function keyType($key)
293 {
294 $keyType = $key . "Type";
295
296 // ensure keyType is a valid class
297 if (property_exists($this, $keyType) && $this->$keyType !== null && class_exists($this->$keyType)) {
298 return $this->$keyType;
299 }
300 }
301
302 protected function dataType($key)
303 {
304 $dataType = $key . "DataType";
305
306 if (property_exists($this, $dataType)) {
307 return $this->$dataType;
308 }
309 }
310
311 public function __isset($key)
312 {
313 return isset($this->modelData[$key]);
314 }
315
316 public function __unset($key)
317 {
318 unset($this->modelData[$key]);
319 }
320
321 /**
322 * Convert a string to camelCase
323 * @param string $value
324 * @return string
325 */
326 private function camelCase($value)
327 {
328 $value = ucwords(str_replace(['-', '_'], ' ', $value));
329 $value = str_replace(' ', '', $value);
330 $value[0] = strtolower($value[0]);
331 return $value;
332 }
333}
Note: See TracBrowser for help on using the repository browser.