/** * @param \Protobuf\Stream $stream * * @return \Protobuf\Stream */ public function compile(Stream $stream) { // Parse the request $request = CodeGeneratorRequest::fromStream($stream, $this->config); $response = new CodeGeneratorResponse(); $context = $this->createContext($request); $entities = $context->getEntities(); $options = $context->getOptions(); $generator = new Generator($context); // whether or not it will renegerate classes with new extensions $regenerate = false; $hasExtension = $context->hasProtobufExtension(); // Run each entity foreach ($entities as $key => $entity) { $generateImported = $options->getGenerateImported(); $isFileToGenerate = $entity->isFileToGenerate(); // Only compile those given to generate, not the imported ones if (!$generateImported && !$isFileToGenerate) { $this->logger->debug(sprintf('Skipping generation of imported class "%s"', $entity->getClass())); continue; } $this->logger->info(sprintf('Generating class "%s"', $entity->getClass())); $generator->visit($entity); $file = new File(); $path = $entity->getPath(); $content = $entity->getContent(); $file->setName($path); $file->setContent($content); $response->addFile($file); if ($hasExtension && $this->loadEntityClass($entity)) { $regenerate = true; } } if ($regenerate) { $this->logger->info('Regenerating classes with new extensions'); $stream->seek(0); // Renegerate classes with new extensions return $this->compile($stream); } $this->logger->info('Generation completed.'); // Finally serialize the response object return $response->toStream($this->config); }
public function handle(CodeGeneratorRequest $request) { $files = array(); foreach ((array) $request->getProtoFile() as $file) { /** @var FileDescriptorProto $file */ $this->collectFile($file, array()); $specClassName = "Skrz\\Meta\\MetaSpec"; $customSpecClassName = false; foreach ($file->getSourceCodeInfo()->getLocation() as $location) { if ($location->getPath() === array(FileDescriptorProtoMeta::PACKAGE_PROTOBUF_FIELD) && $location->getLeadingComments() && preg_match("/@spec\\s+([a-zA-Z0-9_\\\\]+)/", $location->getLeadingComments(), $m)) { $specClassName = $m[1]; $customSpecClassName = true; } } uksort($this->messages, function ($a, $b) { if (strlen($a) === strlen($b)) { return strcmp($b, $a); } return strlen($b) - strlen($a); }); $tmpFiles = array(); foreach ($this->messages as $className => $message) { // compile message file $codeFile = new CodeGeneratorResponse\File(); $codeFile->setName(str_replace("\\", "/", $className) . ".php"); $result = $this->generateMessage($className, $message); $codeFile->setContent((string) $result->getFile()); $files[$className] = $codeFile; // compile meta file if (!class_exists($className)) { $tmpFiles[] = $tmpFile = tempnam(sys_get_temp_dir(), "protoc-gen-php"); file_put_contents($tmpFile, (string) $result->getFile()); require_once $tmpFile; } /** @var AbstractMetaSpec $spec */ $spec = new $specClassName(); if (!$customSpecClassName) { $spec->match($className)->addModule(new ProtobufModule()); } $metaResult = $spec->compile($type = Type::fromString($className)); if ($metaResult !== null) { $metaFile = new CodeGeneratorResponse\File(); $metaFile->setName(str_replace("\\", "/", $spec->createMetaClassName($type)) . ".php"); $metaFile->setContent((string) $metaResult->getFile()); $files[$metaResult->getClass()->getName()] = $metaFile; } } foreach ($tmpFiles as $tmpFile) { unlink($tmpFile); } foreach ($this->enums as $className => $enum) { $enumFile = new CodeGeneratorResponse\File(); $enumFile->setName(str_replace("\\", "/", $className) . ".php"); $result = $this->generateEnum($className, $enum); $enumFile->setContent((string) $result->getFile()); $files[$className] = $enumFile; } } $response = new CodeGeneratorResponse(); $response->setFile($files); return $response; }
public function generate(proto\FileDescriptorProto $proto) { // Keep a reference to the current proto $this->proto = $proto; // Obtain the root namespace $ns = $proto->getPackage(); // Reset the extensions dictionary $this->extensions = array(); $result = array(); // Generate Enums if (!empty($proto->enum_type)) { $result += $this->generateEnums($proto->enum_type, $ns); } // Generate Messages if (!empty($proto->message_type)) { $result += $this->generateMessages($proto->message_type, $ns); } // Collect extensions if (!empty($proto->extension_)) { foreach ($proto->extension_ as $field) { $this->extensions[$field->getExtendee()][] = $field; } } // Generate all extensions found in this proto file if (count($this->extensions)) { // In multifile mode we output all the extensions in a file named after // the proto file, since it's not trivial or even possible in all cases // to include the extensions with the extended message file. $fname = pathinfo($proto->name, PATHINFO_FILENAME) . '-extensions'; $src = array(); foreach ($this->extensions as $extendee => $fields) { $src[] = $this->template('extension', $fields, $extendee); } $result[$fname] = implode("\n", $src); } // Generate services if ($this->option('generic_services') && $proto->hasService()) { foreach ($proto->getServiceList() as $service) { $src = $this->template('service', $service, $ns); $result[$namespace . '.' . $service->getName()] = $src; } } $suffix = $this->option('suffix', '.php'); $files = array(); if ($this->option('multifile', false)) { foreach ($result as $ns => $content) { if (empty($content)) { continue; } // Generate a filename from the mapped namespace $fname = str_replace($this->nsSep, DIRECTORY_SEPARATOR, $this->ns($ns)); $fname .= $suffix; $file = new proto\compiler\CodeGeneratorResponse\File(); $file->setName($fname); $src = $this->template('file', $content, $ns); $file->setContent($src); $files[] = $file; } } else { $fname = pathinfo($proto->name, PATHINFO_FILENAME) . $suffix; $file = new \google\protobuf\compiler\CodeGeneratorResponse\File(); $file->setName($fname); $src = $this->template('file', implode("\n", $result), $ns); $file->setContent($src); $files[] = $file; } return $files; }