@ -66,19 +66,30 @@ class Message
/**
* @ignore
*/
public function __construct($desc = NULL)
public function __construct($data = NULL)
{
// MapEntry message is shared by all types of map fields, whose
// descriptors are different from each other. Thus, we cannot find a
// specific descriptor from the descriptor pool.
if (get_class($this) === 'Google\Protobuf\Internal\MapEntry') {
$this->desc = $desc;
foreach ($desc->getField() as $field) {
$setter = $field->getSetter();
$this->$setter($this->defaultValue($field));
if ($this instanceof MapEntry) {
$this->initWithDescriptor($data);
} else {
$this->initWithGeneratedPool();
if (is_array($data)) {
$this->mergeFromArray($data);
} else if (!empty($data)) {
throw new \InvalidArgumentException(
'Message constructor must be an array or null.'
);
}
return;
}
}
/**
* @ignore
*/
private function initWithGeneratedPool()
{
$pool = DescriptorPool::getGeneratedPool();
$this->desc = $pool->getDescriptorByClassName(get_class($this));
if (is_null($this->desc)) {
@ -151,6 +162,19 @@ class Message
}
}
/**
* @ignore
*/
private function initWithDescriptor(Descriptor $desc)
{
$this->desc = $desc;
foreach ($desc->getField() as $field) {
$setter = $field->getSetter();
$defaultValue = $this->defaultValue($field);
$this->$setter($defaultValue);
}
}
protected function readOneof($number)
{
$field = $this->desc->getFieldByNumber($number);
@ -628,58 +652,58 @@ class Message
*/
public function mergeFrom($msg)
{
if (get_class($this) !== get_class($msg)) {
user_error("Cannot merge messages with different class.");
return;
}
foreach ($this->desc->getField() as $field) {
$setter = $field->getSetter();
$getter = $field->getGetter();
if ($field->isMap()) {
if (count($msg->$getter()) != 0) {
$value_field = $field->getMessageType()->getFieldByNumber(2);
foreach ($msg->$getter() as $key => $value) {
if ($value_field->getType() == GPBType::MESSAGE) {
$klass = $value_field->getMessageType()->getClass();
$copy = new $klass;
$copy->mergeFrom($value);
$this->kvUpdateHelper($field, $key, $copy);
} else {
$this->kvUpdateHelper($field, $key, $value);
}
}
}
} else if ($field->getLabel() === GPBLabel::REPEATED) {
if (count($msg->$getter()) != 0) {
foreach ($msg->$getter() as $tmp) {
if ($field->getType() == GPBType::MESSAGE) {
$klass = $field->getMessageType()->getClass();
$copy = new $klass;
$copy->mergeFrom($tmp);
$this->appendHelper($field, $copy);
} else {
$this->appendHelper($field, $tmp);
}
}
}
} else if ($field->getLabel() === GPBLabel::OPTIONAL) {
if($msg->$getter() !== $this->defaultValue($field)) {
$tmp = $msg->$getter();
if ($field->getType() == GPBType::MESSAGE) {
if (is_null($this->$getter())) {
$klass = $field->getMessageType()->getClass();
$new_msg = new $klass;
$this->$setter($new_msg);
}
$this->$getter()->mergeFrom($tmp);
} else {
$this->$setter($tmp);
}
}
}
}
if (get_class($this) !== get_class($msg)) {
user_error("Cannot merge messages with different class.");
return;
}
foreach ($this->desc->getField() as $field) {
$setter = $field->getSetter();
$getter = $field->getGetter();
if ($field->isMap()) {
if (count($msg->$getter()) != 0) {
$value_field = $field->getMessageType()->getFieldByNumber(2);
foreach ($msg->$getter() as $key => $value) {
if ($value_field->getType() == GPBType::MESSAGE) {
$klass = $value_field->getMessageType()->getClass();
$copy = new $klass;
$copy->mergeFrom($value);
$this->kvUpdateHelper($field, $key, $copy);
} else {
$this->kvUpdateHelper($field, $key, $value);
}
}
}
} else if ($field->getLabel() === GPBLabel::REPEATED) {
if (count($msg->$getter()) != 0) {
foreach ($msg->$getter() as $tmp) {
if ($field->getType() == GPBType::MESSAGE) {
$klass = $field->getMessageType()->getClass();
$copy = new $klass;
$copy->mergeFrom($tmp);
$this->appendHelper($field, $copy);
} else {
$this->appendHelper($field, $tmp);
}
}
}
} else if ($field->getLabel() === GPBLabel::OPTIONAL) {
if($msg->$getter() !== $this->defaultValue($field)) {
$tmp = $msg->$getter();
if ($field->getType() == GPBType::MESSAGE) {
if (is_null($this->$getter())) {
$klass = $field->getMessageType()->getClass();
$new_msg = new $klass;
$this->$setter($new_msg);
}
$this->$getter()->mergeFrom($tmp);
} else {
$this->$setter($tmp);
}
}
}
}
}
/**
@ -763,7 +787,8 @@ class Message
try {
$timestamp = GPBUtil::parseTimestamp($value);
} catch (\Exception $e) {
throw new GPBDecodeException("Invalid RFC 3339 timestamp: ".$e->getMessage());
throw new GPBDecodeException(
"Invalid RFC 3339 timestamp: ".$e->getMessage());
}
$submsg->setSeconds($timestamp->getSeconds());
@ -775,7 +800,8 @@ class Message
try {
return GPBUtil::parseFieldMask($value);
} catch (\Exception $e) {
throw new GPBDecodeException("Invalid FieldMask: ".$e->getMessage());
throw new GPBDecodeException(
"Invalid FieldMask: ".$e->getMessage());
}
} else {
if (is_null($value) & &
@ -792,21 +818,23 @@ class Message
case GPBType::ENUM:
if (is_null($value)) {
return $this->defaultValue($field);
} else if (is_integer($value)) {
}
if (is_integer($value)) {
return $value;
} else {
$enum_value =
$field->getEnumType()->getValueByName($value);
}
$enum_value = $field->getEnumType()->getValueByName($value);
if (!is_null($enum_value)) {
return $enum_value->getNumber();
}
throw new GPBDecodeException(
"Enum field only accepts integer or enum value name");
case GPBType::STRING:
if (is_null($value)) {
return $this->defaultValue($field);
}
if (!is_string($value)) {
throw new GPBDecodeException("Expect string");
throw new GPBDecodeException(
"String field only accepts string value");
}
return $value;
case GPBType::BYTES:
@ -814,12 +842,12 @@ class Message
return $this->defaultValue($field);
}
if (!is_string($value)) {
throw new GPBDecodeException("Expect string");
throw new GPBDecodeException(
"Byte field only accepts string value");
}
$proto_value = base64_decode($value, true);
if ($proto_value === false) {
throw new GPBDecodeException(
"Invalid base64 characters");
throw new GPBDecodeException("Invalid base64 characters");
}
return $proto_value;
case GPBType::BOOL:
@ -834,27 +862,14 @@ class Message
return false;
}
throw new GPBDecodeException(
"Bool field only accept bool value");
"Bool field only accepts bool value");
}
if (!is_bool($value)) {
throw new GPBDecodeException(
"Bool field only accept bool value");
"Bool field only accepts bool value");
}
return $value;
case GPBType::FLOAT:
if (is_null($value)) {
return $this->defaultValue($field);
}
if ($value === "Infinity") {
return INF;
}
if ($value === "-Infinity") {
return -INF;
}
if ($value === "NaN") {
return NAN;
}
return $value;
case GPBType::DOUBLE:
if (is_null($value)) {
return $this->defaultValue($field);
@ -943,6 +958,39 @@ class Message
}
}
/**
* Populates the message from a user-supplied PHP array. Array keys
* correspond to Message properties and nested message properties.
*
* Example:
* ```
* $message->mergeFromArray([
* 'name' => 'This is a message name',
* 'interval' => [
* 'startTime' => time() - 60,
* 'endTime' => time(),
* ]
* ]);
* ```
*
* @param array $array An array containing message properties and values.
* @return null.
* @throws Exception Invalid data.
*/
protected function mergeFromArray(array $array)
{
// Just call the setters for the field names
foreach ($array as $key => $value) {
$field = $this->desc->getFieldByName($key);
if (is_null($field)) {
throw new \UnexpectedValueException(
'Invalid message property: ' . $key);
}
$setter = $field->getSetter();
$this->$setter($value);
}
}
protected function mergeFromJsonArray($array)
{
if (is_a($this, "Google\Protobuf\Any")) {
@ -1035,6 +1083,11 @@ class Message
}
return;
}
$this->mergeFromArrayJsonImpl($array);
}
private function mergeFromArrayJsonImpl($array)
{
foreach ($array as $key => $value) {
$field = $this->desc->getFieldByJsonName($key);
if (is_null($field)) {
@ -1043,7 +1096,6 @@ class Message
continue;
}
}
$setter = $field->getSetter();
if ($field->isMap()) {
if (is_null($value)) {
continue;
@ -1055,15 +1107,13 @@ class Message
throw new \Exception(
"Map value field element cannot be null.");
}
$proto_key =
$this->convertJsonValueToProtoValue(
$tmp_key,
$key_field,
true);
$proto_value =
$this->convertJsonValueToProtoValue(
$tmp_value,
$value_field);
$proto_key = $this->convertJsonValueToProtoValue(
$tmp_key,
$key_field,
true);
$proto_value = $this->convertJsonValueToProtoValue(
$tmp_value,
$value_field);
self::kvUpdateHelper($field, $proto_key, $proto_value);
}
} else if ($field->isRepeated()) {
@ -1075,14 +1125,16 @@ class Message
throw new \Exception(
"Repeated field elements cannot be null.");
}
$proto_value =
$this->convertJsonValueToProtoValue($tmp, $field);
$proto_value = $this->convertJsonValueToProtoValue(
$tmp,
$field);
self::appendHelper($field, $proto_value);
}
} else {
$setter = $field->getSetter();
$proto_value =
$this->convertJsonValueToProtoValue($value, $field);
$proto_value = $this->convertJsonValueToProtoValue(
$value,
$field);
if ($field->getType() === GPBType::MESSAGE) {
if (is_null($proto_value)) {
continue;