/** * @param \Protobuf\Compiler\Entity $entity * * @return string[] */ protected function generateExtensionsSerializedSize(Entity $entity) { $descriptor = $entity->getDescriptor(); $extensionsField = $this->getUniqueFieldName($descriptor, 'extensions'); $body[] = 'if ($this->' . $extensionsField . ' !== null) {'; $body[] = ' $size += $this->' . $extensionsField . '->serializedSize($context);'; $body[] = '}'; return $body; }
/** * @param \Protobuf\Compiler\Entity $entity * * @return string[] */ protected function generateExtensionFields(Entity $entity) { $properties = []; $descriptor = $entity->getDescriptor(); $extensions = $descriptor->getExtensionList() ?: []; foreach ($extensions as $field) { $properties[] = $this->generateExtensionField($entity, $field); } return $properties; }
/** * @param \Protobuf\Compiler\Entity $entity * * @return string[] */ protected function generateMethods(Entity $entity) { $result = []; $descriptor = $entity->getDescriptor(); $methods = $descriptor->getMethodList() ?: []; foreach ($methods as $method) { $result[] = $this->generateMethod($entity, $method); } return $result; }
/** * @param Entity $entity */ public function visit(Entity $entity) { $type = $entity->getType(); $class = $entity->getNamespacedName(); $path = $this->getPsr4ClassPath($class); $entity->setPath($path); if (!isset($this->generators[$type])) { return; } $this->generators[$type]->visit($entity); }
/** * @param \Protobuf\Compiler\Entity $entity * * @return string[] */ public function generateBody(Entity $entity) { $body = []; $descriptor = $entity->getDescriptor(); $fields = $descriptor->getFieldList() ?: []; foreach ($fields as $field) { $name = $field->getName(); $value = $this->getDefaultFieldValue($field); $body[] = sprintf('$this->%s = %s;', $name, $value); } return $body; }
/** * @param \Protobuf\Compiler\Entity $entity * * @return bool */ public function hasDefaultValue(Entity $entity) { $descriptor = $entity->getDescriptor(); $fields = $descriptor->getFieldList() ?: []; foreach ($fields as $field) { if (!$field->hasDefaultValue()) { continue; } return true; } return false; }
/** * @param \Protobuf\Compiler\Entity $entity * @param \google\protobuf\FieldDescriptorProto $field * * @return string[] */ protected function generateRequiredFieldException(Entity $entity, FieldDescriptorProto $field) { $name = $field->getName(); $label = $field->getLabel(); $tag = $field->getNumber(); $isRequired = $label === Label::LABEL_REQUIRED(); if (!$isRequired) { return []; } $class = $entity->getNamespacedName(); $format = 'Field "%s#%s" (tag %s) is required but has no value.'; $message = var_export(sprintf($format, $class, $name, $tag), true); $body[] = 'if ($this->' . $name . ' === null) {'; $body[] = ' throw new \\UnexpectedValueException(' . $message . ');'; $body[] = '}'; $body[] = null; return $body; }
/** * @param \Protobuf\Compiler\Entity $entity * * @return string[] */ public function generateBody(Entity $entity) { $lines = []; $descriptor = $entity->getDescriptor(); $class = $entity->getNamespacedName(); $fields = $descriptor->getFieldList() ?: []; $message = var_export("Argument 1 passed to %s must be a %s, %s given", true); $exception = 'sprintf(' . $message . ', __METHOD__, __CLASS__, get_class($message))'; $lines[] = 'if ( ! $message instanceof ' . $class . ') {'; $lines[] = ' throw new \\InvalidArgumentException(' . $exception . ');'; $lines[] = '}'; $lines[] = null; foreach ($fields as $field) { $item = $this->generateFieldMerge($entity, $field); $lines = array_merge($lines, $item); } return $lines; }
/** * @param \Protobuf\Compiler\Entity $entity * * @return string[] */ protected function generateInnerLoop(Entity $entity) { $descriptor = $entity->getDescriptor(); $fields = $descriptor->getFieldList() ?: []; $body[] = null; $body[] = 'if ($stream->eof()) {'; $body[] = ' break;'; $body[] = '}'; $body[] = null; $body[] = '$key = $reader->readVarint($stream);'; $body[] = '$wire = \\Protobuf\\WireFormat::getTagWireType($key);'; $body[] = '$tag = \\Protobuf\\WireFormat::getTagFieldNumber($key);'; $body[] = null; $body[] = 'if ($stream->eof()) {'; $body[] = ' break;'; $body[] = '}'; $body[] = null; foreach ($fields as $field) { $lines = $this->generateFieldCondition($entity, $field); $body = array_merge($body, $lines); } $unknowFieldName = $this->getUniqueFieldName($descriptor, 'unknownFieldSet'); $extensionsFieldName = $this->getUniqueFieldName($descriptor, 'extensions'); $body[] = '$extensions = $context->getExtensionRegistry();'; $body[] = '$extension = $extensions ? $extensions->findByNumber(__CLASS__, $tag) : null;'; $body[] = null; $body[] = 'if ($extension !== null) {'; $body[] = ' $this->extensions()->add($extension, $extension->readFrom($context, $wire));'; $body[] = null; $body[] = ' continue;'; $body[] = '}'; $body[] = null; $body[] = 'if ($this->' . $unknowFieldName . ' === null) {'; $body[] = ' $this->' . $unknowFieldName . ' = new \\Protobuf\\UnknownFieldSet();'; $body[] = '}'; $body[] = null; $body[] = '$data = $reader->readUnknown($stream, $wire);'; $body[] = '$unknown = new \\Protobuf\\Unknown($tag, $wire, $data);'; $body[] = null; $body[] = '$this->' . $unknowFieldName . '->add($unknown);'; return $body; }
/** * {@inheritdoc} */ public function visit(Entity $entity) { $name = $entity->getName(); $namespace = $entity->getNamespace(); $descriptor = $entity->getDescriptor(); $shortDescription = 'Protobuf message : ' . $entity->getClass(); $class = ClassGenerator::fromArray(['name' => $name, 'namespacename' => $namespace, 'extendedClass' => '\\Protobuf\\AbstractMessage', 'docblock' => ['shortDescription' => $shortDescription]]); foreach ($this->generators as $generator) { $generator->visit($entity, $class); } $entity->setContent($this->generateFileContent($class, $entity)); }
/** * @param \Protobuf\Compiler\Entity $entity * * @return array */ protected function generateDefaultValues(Entity $entity) { $descriptor = $entity->getDescriptor(); $fields = $descriptor->getFieldList() ?: []; $size = count($fields); $lines = []; foreach ($fields as $i => $field) { $name = $field->getName(); $comma = $i + 1 < $size ? ',' : ''; $value = $this->getDefaultFieldValue($field); // required field throw InvalidArgumentException if ($field->getLabel() === Label::LABEL_REQUIRED()) { continue; } if ($field->getLabel() === Label::LABEL_REPEATED()) { $value = '[]'; } $lines[] = "'{$name}' => {$value}" . $comma; } return $lines; }
/** * @param \Protobuf\Compiler\Entity $entity * * @return bool */ protected function loadEntityClass(Entity $entity) { $type = $entity->getType(); $content = $entity->getContent(); $class = $entity->getNamespacedName(); if (class_exists($class) || interface_exists($class)) { return false; } $this->logger->info(sprintf('Loading class "%s"', $class)); $tempname = tempnam(sys_get_temp_dir(), 'proto') . '.php'; file_put_contents($tempname, $content); include $tempname; @unlink($tempname); if ($type === Entity::TYPE_EXTENSION) { $this->logger->info(sprintf('Registering extension "%s"', $class)); $config = $this->config; $registry = $config->getExtensionRegistry(); $class::registerAllExtensions($registry); return true; } return false; }
/** * @param \Protobuf\Compiler\Entity $entity * * @return string */ protected function generateGetExtensionsMethod(Entity $entity) { $lines = []; $descriptor = $entity->getDescriptor(); $fieldName = $this->getUniqueFieldName($descriptor, 'extensions'); $lines[] = 'if ( $this->' . $fieldName . ' !== null) {'; $lines[] = ' return $this->' . $fieldName . ';'; $lines[] = '}'; $lines[] = null; $lines[] = 'return $this->' . $fieldName . ' = new \\Protobuf\\Extension\\ExtensionFieldMap(__CLASS__);'; return MethodGenerator::fromArray(['name' => 'extensions', 'body' => implode(PHP_EOL, $lines), 'docblock' => ['shortDescription' => "{@inheritdoc}"]]); }
/** * @param \Protobuf\Compiler\Entity $entity * * @return string */ protected function generateRegisterAllExtensionsMethod(Entity $entity) { $lines = []; $fields = []; $descriptor = $entity->getDescriptor(); $extensions = $descriptor->getExtensionList() ?: []; $messages = $descriptor->getMessageTypeList() ?: []; foreach ($messages as $message) { if (!$message->hasExtensionList()) { continue; } foreach ($message->getExtensionList() as $extension) { $fields[] = $extension; } } foreach ($fields as $field) { $type = $field->getTypeName(); $name = $this->getCamelizedName($field); $ref = $this->getEntity($type); $class = $ref->getNamespacedName(); $lines[] = '$registry->add(' . $class . '::' . $name . '());'; } foreach ($extensions as $field) { $type = $field->getTypeName(); $name = $this->getCamelizedName($field); $lines[] = '$registry->add(self::' . $name . '());'; } $body = implode(PHP_EOL, $lines); $method = MethodGenerator::fromArray(['static' => true, 'body' => $body, 'name' => 'registerAllExtensions', 'parameters' => [['name' => 'registry', 'type' => '\\Protobuf\\Extension\\ExtensionRegistry']], 'docblock' => ['shortDescription' => "Register all extensions", 'tags' => [['name' => 'param', 'description' => '\\Protobuf\\Extension\\ExtensionRegistry']]]]); return $method; }
/** * @param \Protobuf\Compiler\Entity $entity * * @return string */ public function generateValueOfMethod(Entity $entity) { $body = []; $descriptor = $entity->getDescriptor(); $class = $entity->getNamespacedName(); $values = $descriptor->getValueList() ?: []; $body[] = 'switch ($value) {'; foreach ($values as $value) { $name = $value->getName(); $number = $value->getNumber(); $body[] = ' case ' . $number . ': return self::' . $name . '();'; } $body[] = ' default: return null;'; $body[] = '}'; $method = MethodGenerator::fromArray(['static' => true, 'name' => 'valueOf', 'body' => implode(PHP_EOL, $body), 'parameters' => [['name' => 'value', 'type' => 'int']], 'docblock' => ['tags' => [['name' => 'param', 'description' => 'int $value'], ['name' => 'return', 'description' => $class]]]]); $method->getDocblock()->setWordWrap(false); return $method; }
public function testGetNamespacedName() { $name = 'SimpleMessage'; $type = Entity::TYPE_MESSAGE; $descriptor = new DescriptorProto(); $fileDescriptor1 = new FileDescriptorProto(); $fileDescriptor2 = new FileDescriptorProto(); $fileDescriptor3 = new FileDescriptorProto(); $fileDescriptor2->setPackage('package'); $fileDescriptor3->setPackage('package'); $entity1 = new Entity($type, $name, $descriptor, $fileDescriptor1); $entity2 = new Entity($type, $name, $descriptor, $fileDescriptor2); $entity3 = new Entity($type, $name, $descriptor, $fileDescriptor3, 'Parent'); $this->assertEquals('\\SimpleMessage', $entity1->getNamespacedName()); $this->assertEquals('\\package\\SimpleMessage', $entity2->getNamespacedName()); $this->assertEquals('\\package\\Parent\\SimpleMessage', $entity3->getNamespacedName()); }
/** * @param \Protobuf\Compiler\Entity $entity * * @return string[] */ protected function createOptionsBody(Entity $entity) { $descriptor = $entity->getDescriptor(); $values = []; $lines = []; $options = $descriptor->getOptions(); $extensions = $options->extensions(); $lines[] = '$options = \\google\\protobuf\\MessageOptions::fromArray(['; $lines = array_merge($lines, $this->generateArrayLines($values)); $lines[] = ']);'; $lines[] = null; for ($extensions->rewind(); $extensions->valid(); $extensions->next()) { $extension = $extensions->current(); $info = $extensions->getInfo(); $method = '\\' . $extension->getMethod(); $value = var_export($info, true); $name = $extension->getName(); if (is_object($info)) { $value = '\\' . $value; } $lines[] = '$options->extensions()->add(' . $method . '(), ' . $value . ');'; } return $lines; }
/** * @param \google\protobuf\FileDescriptorProto $fileDescriptor * @param \google\protobuf\DescriptorProto $messageDescriptor * @param string $parent * * @return \Protobuf\Compiler\Entity */ protected function generateMessage(FileDescriptorProto $fileDescriptor, DescriptorProto $messageDescriptor, $parent = null) { $type = Entity::TYPE_MESSAGE; $name = $messageDescriptor->getName(); $entity = new Entity($type, $name, $messageDescriptor, $fileDescriptor, $parent); if ($messageDescriptor->hasExtensionList() && $this->containsProtobufExtension($messageDescriptor->getExtensionList())) { $entity->setProtobufExtension(true); } return $entity; }