• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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