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