1<?php 2 3// Protocol Buffers - Google's data interchange format 4// Copyright 2008 Google Inc. All rights reserved. 5// 6// Use of this source code is governed by a BSD-style 7// license that can be found in the LICENSE file or at 8// https://developers.google.com/open-source/licenses/bsd 9 10namespace Google\Protobuf\Internal; 11 12class FieldDescriptor 13{ 14 use HasPublicDescriptorTrait; 15 16 private $name; 17 private $json_name; 18 private $setter; 19 private $getter; 20 private $number; 21 private $label; 22 private $type; 23 private $message_type; 24 private $enum_type; 25 private $packed; 26 private $oneof_index = -1; 27 private $proto3_optional; 28 29 /** @var OneofDescriptor $containing_oneof */ 30 private $containing_oneof; 31 32 public function __construct() 33 { 34 $this->public_desc = new \Google\Protobuf\FieldDescriptor($this); 35 } 36 37 public function setOneofIndex($index) 38 { 39 $this->oneof_index = $index; 40 } 41 42 public function getOneofIndex() 43 { 44 return $this->oneof_index; 45 } 46 47 public function setName($name) 48 { 49 $this->name = $name; 50 } 51 52 public function getName() 53 { 54 return $this->name; 55 } 56 57 public function setJsonName($json_name) 58 { 59 $this->json_name = $json_name; 60 } 61 62 public function getJsonName() 63 { 64 return $this->json_name; 65 } 66 67 public function setSetter($setter) 68 { 69 $this->setter = $setter; 70 } 71 72 public function getSetter() 73 { 74 return $this->setter; 75 } 76 77 public function setGetter($getter) 78 { 79 $this->getter = $getter; 80 } 81 82 public function getGetter() 83 { 84 return $this->getter; 85 } 86 87 public function setNumber($number) 88 { 89 $this->number = $number; 90 } 91 92 public function getNumber() 93 { 94 return $this->number; 95 } 96 97 public function setLabel($label) 98 { 99 $this->label = $label; 100 } 101 102 public function getLabel() 103 { 104 return $this->label; 105 } 106 107 public function isRepeated() 108 { 109 return $this->label === GPBLabel::REPEATED; 110 } 111 112 public function setType($type) 113 { 114 $this->type = $type; 115 } 116 117 public function getType() 118 { 119 return $this->type; 120 } 121 122 public function setMessageType($message_type) 123 { 124 $this->message_type = $message_type; 125 } 126 127 public function getMessageType() 128 { 129 return $this->message_type; 130 } 131 132 public function setEnumType($enum_type) 133 { 134 $this->enum_type = $enum_type; 135 } 136 137 public function getEnumType() 138 { 139 return $this->enum_type; 140 } 141 142 public function setPacked($packed) 143 { 144 $this->packed = $packed; 145 } 146 147 public function getPacked() 148 { 149 return $this->packed; 150 } 151 152 public function getProto3Optional() 153 { 154 return $this->proto3_optional; 155 } 156 157 public function setProto3Optional($proto3_optional) 158 { 159 $this->proto3_optional = $proto3_optional; 160 } 161 162 public function getContainingOneof() 163 { 164 return $this->containing_oneof; 165 } 166 167 public function setContainingOneof($containing_oneof) 168 { 169 $this->containing_oneof = $containing_oneof; 170 } 171 172 public function getRealContainingOneof() 173 { 174 return !is_null($this->containing_oneof) && !$this->containing_oneof->isSynthetic() 175 ? $this->containing_oneof : null; 176 } 177 178 public function isPackable() 179 { 180 return $this->isRepeated() && self::isTypePackable($this->type); 181 } 182 183 public function isMap() 184 { 185 return $this->getType() == GPBType::MESSAGE && 186 !is_null($this->getMessageType()->getOptions()) && 187 $this->getMessageType()->getOptions()->getMapEntry(); 188 } 189 190 public function isTimestamp() 191 { 192 return $this->getType() == GPBType::MESSAGE && 193 $this->getMessageType()->getClass() === "Google\Protobuf\Timestamp"; 194 } 195 196 public function isWrapperType() 197 { 198 if ($this->getType() == GPBType::MESSAGE) { 199 $class = $this->getMessageType()->getClass(); 200 return in_array($class, [ 201 "Google\Protobuf\DoubleValue", 202 "Google\Protobuf\FloatValue", 203 "Google\Protobuf\Int64Value", 204 "Google\Protobuf\UInt64Value", 205 "Google\Protobuf\Int32Value", 206 "Google\Protobuf\UInt32Value", 207 "Google\Protobuf\BoolValue", 208 "Google\Protobuf\StringValue", 209 "Google\Protobuf\BytesValue", 210 ]); 211 } 212 return false; 213 } 214 215 private static function isTypePackable($field_type) 216 { 217 return ($field_type !== GPBType::STRING && 218 $field_type !== GPBType::GROUP && 219 $field_type !== GPBType::MESSAGE && 220 $field_type !== GPBType::BYTES); 221 } 222 223 /** 224 * @param FieldDescriptorProto $proto 225 * @return FieldDescriptor 226 */ 227 public static function getFieldDescriptor($proto) 228 { 229 $type_name = null; 230 $type = $proto->getType(); 231 switch ($type) { 232 case GPBType::MESSAGE: 233 case GPBType::GROUP: 234 case GPBType::ENUM: 235 $type_name = $proto->getTypeName(); 236 break; 237 default: 238 break; 239 } 240 241 $oneof_index = $proto->hasOneofIndex() ? $proto->getOneofIndex() : -1; 242 // TODO: once proto2 is supported, this default should be false 243 // for proto2. 244 if ($proto->getLabel() === GPBLabel::REPEATED && 245 $proto->getType() !== GPBType::MESSAGE && 246 $proto->getType() !== GPBType::GROUP && 247 $proto->getType() !== GPBType::STRING && 248 $proto->getType() !== GPBType::BYTES) { 249 $packed = true; 250 } else { 251 $packed = false; 252 } 253 $options = $proto->getOptions(); 254 if ($options !== null) { 255 $packed = $options->getPacked(); 256 } 257 258 $field = new FieldDescriptor(); 259 $field->setName($proto->getName()); 260 261 if ($proto->hasJsonName()) { 262 $json_name = $proto->getJsonName(); 263 } else { 264 $proto_name = $proto->getName(); 265 $json_name = implode('', array_map('ucwords', explode('_', $proto_name))); 266 if ($proto_name[0] !== "_" && !ctype_upper($proto_name[0])) { 267 $json_name = lcfirst($json_name); 268 } 269 } 270 $field->setJsonName($json_name); 271 272 $camel_name = implode('', array_map('ucwords', explode('_', $proto->getName()))); 273 $field->setGetter('get' . $camel_name); 274 $field->setSetter('set' . $camel_name); 275 $field->setType($proto->getType()); 276 $field->setNumber($proto->getNumber()); 277 $field->setLabel($proto->getLabel()); 278 $field->setPacked($packed); 279 $field->setOneofIndex($oneof_index); 280 $field->setProto3Optional($proto->getProto3Optional()); 281 282 // At this time, the message/enum type may have not been added to pool. 283 // So we use the type name as place holder and will replace it with the 284 // actual descriptor in cross building. 285 switch ($type) { 286 case GPBType::MESSAGE: 287 $field->setMessageType($type_name); 288 break; 289 case GPBType::ENUM: 290 $field->setEnumType($type_name); 291 break; 292 default: 293 break; 294 } 295 296 return $field; 297 } 298 299 public static function buildFromProto($proto) 300 { 301 return FieldDescriptor::getFieldDescriptor($proto); 302 } 303} 304