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