xref: /aosp_15_r20/external/grpc-grpc/src/compiler/php_generator.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 /*
2  *
3  * Copyright 2016 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <map>
20 
21 #include <google/protobuf/compiler/php/php_generator.h>
22 
23 #include "src/compiler/config.h"
24 #include "src/compiler/generator_helpers.h"
25 #include "src/compiler/php_generator_helpers.h"
26 
27 using google::protobuf::compiler::php::GeneratedClassName;
28 using grpc::protobuf::Descriptor;
29 using grpc::protobuf::FileDescriptor;
30 using grpc::protobuf::MethodDescriptor;
31 using grpc::protobuf::ServiceDescriptor;
32 using grpc::protobuf::io::Printer;
33 using grpc::protobuf::io::StringOutputStream;
34 using std::map;
35 
36 namespace grpc_php_generator {
37 namespace {
38 
ConvertToPhpNamespace(const std::string & name)39 std::string ConvertToPhpNamespace(const std::string& name) {
40   std::vector<std::string> tokens = grpc_generator::tokenize(name, ".");
41   std::ostringstream oss;
42   for (unsigned int i = 0; i < tokens.size(); i++) {
43     oss << (i == 0 ? "" : "\\")
44         << grpc_generator::CapitalizeFirstLetter(tokens[i]);
45   }
46   return oss.str();
47 }
48 
PackageName(const FileDescriptor * file)49 std::string PackageName(const FileDescriptor* file) {
50   if (file->options().has_php_namespace()) {
51     return file->options().php_namespace();
52   } else {
53     return ConvertToPhpNamespace(file->package());
54   }
55 }
56 
MessageIdentifierName(const std::string & name,const FileDescriptor * file)57 std::string MessageIdentifierName(const std::string& name,
58                                   const FileDescriptor* file) {
59   std::vector<std::string> tokens = grpc_generator::tokenize(name, ".");
60   std::ostringstream oss;
61   if (PackageName(file) != "") {
62     oss << PackageName(file) << "\\";
63   }
64   oss << grpc_generator::CapitalizeFirstLetter(tokens[tokens.size() - 1]);
65   return oss.str();
66 }
67 
PrintMethod(const MethodDescriptor * method,Printer * out)68 void PrintMethod(const MethodDescriptor* method, Printer* out) {
69   const Descriptor* input_type = method->input_type();
70   const Descriptor* output_type = method->output_type();
71   map<std::string, std::string> vars;
72   vars["service_name"] = method->service()->full_name();
73   vars["name"] = method->name();
74   vars["input_type_id"] =
75       MessageIdentifierName(GeneratedClassName(input_type), input_type->file());
76   vars["output_type_id"] = MessageIdentifierName(
77       GeneratedClassName(output_type), output_type->file());
78 
79   out->Print("/**\n");
80   if (method->options().deprecated()) {
81     out->Print(" * @deprecated\n");
82   }
83   out->Print(GetPHPComments(method, " *").c_str());
84   if (method->client_streaming()) {
85     if (method->server_streaming()) {
86       vars["return_type_id"] = "\\Grpc\\BidiStreamingCall";
87     } else {
88       vars["return_type_id"] = "\\Grpc\\ClientStreamingCall";
89     }
90     out->Print(vars,
91                " * @param array $$metadata metadata\n"
92                " * @param array $$options call options\n"
93                " * @return $return_type_id$\n */\n"
94                "public function $name$($$metadata = [], "
95                "$$options = []) {\n");
96     out->Indent();
97     out->Indent();
98     if (method->server_streaming()) {
99       out->Print("return $$this->_bidiRequest(");
100     } else {
101       out->Print("return $$this->_clientStreamRequest(");
102     }
103     out->Print(vars,
104                "'/$service_name$/$name$',\n"
105                "['\\$output_type_id$','decode'],\n"
106                "$$metadata, $$options);\n");
107   } else {
108     if (method->server_streaming()) {
109       vars["return_type_id"] = "\\Grpc\\ServerStreamingCall";
110     } else {
111       vars["return_type_id"] = "\\Grpc\\UnaryCall";
112     }
113     out->Print(vars,
114                " * @param \\$input_type_id$ $$argument input argument\n"
115                " * @param array $$metadata metadata\n"
116                " * @param array $$options call options\n"
117                " * @return $return_type_id$\n */\n"
118                "public function $name$(\\$input_type_id$ $$argument,\n"
119                "  $$metadata = [], $$options = []) {\n");
120     out->Indent();
121     out->Indent();
122     if (method->server_streaming()) {
123       out->Print("return $$this->_serverStreamRequest(");
124     } else {
125       out->Print("return $$this->_simpleRequest(");
126     }
127     out->Print(vars,
128                "'/$service_name$/$name$',\n"
129                "$$argument,\n"
130                "['\\$output_type_id$', 'decode'],\n"
131                "$$metadata, $$options);\n");
132   }
133   out->Outdent();
134   out->Outdent();
135   out->Print("}\n\n");
136 }
137 
PrintServerMethod(const MethodDescriptor * method,Printer * out)138 void PrintServerMethod(const MethodDescriptor* method, Printer* out) {
139   map<std::string, std::string> vars;
140   const Descriptor* input_type = method->input_type();
141   const Descriptor* output_type = method->output_type();
142   vars["service_name"] = method->service()->full_name();
143   vars["method_name"] = method->name();
144   vars["input_type_id"] =
145       MessageIdentifierName(GeneratedClassName(input_type), input_type->file());
146   vars["output_type_id"] = MessageIdentifierName(
147       GeneratedClassName(output_type), output_type->file());
148 
149   out->Print("/**\n");
150   if (method->options().deprecated()) {
151     out->Print(" * @deprecated\n");
152   }
153   out->Print(GetPHPComments(method, " *").c_str());
154 
155   const char* method_template;
156   if (method->client_streaming() && method->server_streaming()) {
157     method_template =
158         " * @param \\Grpc\\ServerCallReader $$reader read client request data "
159         "of \\$input_type_id$\n"
160         " * @param \\Grpc\\ServerCallWriter $$writer write response data of "
161         "\\$output_type_id$\n"
162         " * @param \\Grpc\\ServerContext $$context server request context\n"
163         " * @return void\n"
164         " */\n"
165         "public function $method_name$(\n"
166         "    \\Grpc\\ServerCallReader $$reader,\n"
167         "    \\Grpc\\ServerCallWriter $$writer,\n"
168         "    \\Grpc\\ServerContext $$context\n"
169         "): void {\n"
170         "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
171         "    $$writer->finish();\n"
172         "}\n\n";
173   } else if (method->client_streaming()) {
174     method_template =
175         " * @param \\Grpc\\ServerCallReader $$reader read client request data "
176         "of \\$input_type_id$\n"
177         " * @param \\Grpc\\ServerContext $$context server request context\n"
178         " * @return \\$output_type_id$ for response data, null if if error "
179         "occured\n"
180         " *     initial metadata (if any) and status (if not ok) should be set "
181         "to $$context\n"
182         " */\n"
183         "public function $method_name$(\n"
184         "    \\Grpc\\ServerCallReader $$reader,\n"
185         "    \\Grpc\\ServerContext $$context\n"
186         "): ?\\$output_type_id$ {\n"
187         "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
188         "    return null;\n"
189         "}\n\n";
190   } else if (method->server_streaming()) {
191     method_template =
192         " * @param \\$input_type_id$ $$request client request\n"
193         " * @param \\Grpc\\ServerCallWriter $$writer write response data of "
194         "\\$output_type_id$\n"
195         " * @param \\Grpc\\ServerContext $$context server request context\n"
196         " * @return void\n"
197         " */\n"
198         "public function $method_name$(\n"
199         "    \\$input_type_id$ $$request,\n"
200         "    \\Grpc\\ServerCallWriter $$writer,\n"
201         "    \\Grpc\\ServerContext $$context\n"
202         "): void {\n"
203         "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
204         "    $$writer->finish();\n"
205         "}\n\n";
206   } else {
207     method_template =
208         " * @param \\$input_type_id$ $$request client request\n"
209         " * @param \\Grpc\\ServerContext $$context server request context\n"
210         " * @return \\$output_type_id$ for response data, null if if error "
211         "occured\n"
212         " *     initial metadata (if any) and status (if not ok) should be set "
213         "to $$context\n"
214         " */\n"
215         "public function $method_name$(\n"
216         "    \\$input_type_id$ $$request,\n"
217         "    \\Grpc\\ServerContext $$context\n"
218         "): ?\\$output_type_id$ {\n"
219         "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
220         "    return null;\n"
221         "}\n\n";
222   }
223   out->Print(vars, method_template);
224 }
225 
PrintServerMethodDescriptors(const ServiceDescriptor * service,Printer * out)226 void PrintServerMethodDescriptors(const ServiceDescriptor* service,
227                                   Printer* out) {
228   map<std::string, std::string> vars;
229   vars["service_name"] = service->full_name();
230 
231   out->Print("/**\n");
232   if (service->options().deprecated()) {
233     out->Print(" * @deprecated\n");
234   }
235   out->Print(
236       " * Get the method descriptors of the service for server registration\n"
237       " *\n"
238       " * @return array of \\Grpc\\MethodDescriptor for the service methods\n"
239       " */\n"
240       "public final function getMethodDescriptors(): array\n{\n");
241   out->Indent();
242   out->Indent();
243   out->Print("return [\n");
244   out->Indent();
245   out->Indent();
246   for (int i = 0; i < service->method_count(); i++) {
247     auto method = service->method(i);
248     auto input_type = method->input_type();
249     vars["method_name"] = method->name();
250     vars["input_type_id"] = MessageIdentifierName(
251         GeneratedClassName(input_type), input_type->file());
252     if (method->client_streaming() && method->server_streaming()) {
253       vars["call_type"] = "BIDI_STREAMING_CALL";
254     } else if (method->client_streaming()) {
255       vars["call_type"] = "CLIENT_STREAMING_CALL";
256     } else if (method->server_streaming()) {
257       vars["call_type"] = "SERVER_STREAMING_CALL";
258     } else {
259       vars["call_type"] = "UNARY_CALL";
260     }
261     out->Print(
262         vars,
263         "'/$service_name$/$method_name$' => new \\Grpc\\MethodDescriptor(\n"
264         "    $$this,\n"
265         "    '$method_name$',\n"
266         "    '\\$input_type_id$',\n"
267         "    \\Grpc\\MethodDescriptor::$call_type$\n"
268         "),\n");
269   }
270   out->Outdent();
271   out->Outdent();
272   out->Print("];\n");
273   out->Outdent();
274   out->Outdent();
275   out->Print("}\n\n");
276 }
277 
278 // Prints out the service descriptor object
PrintService(const ServiceDescriptor * service,const std::string & class_suffix,bool is_server,Printer * out)279 void PrintService(const ServiceDescriptor* service,
280                   const std::string& class_suffix, bool is_server,
281                   Printer* out) {
282   map<std::string, std::string> vars;
283   out->Print("/**\n");
284   if (service->options().deprecated()) {
285     out->Print(" * @deprecated\n");
286   }
287   out->Print(GetPHPComments(service, " *").c_str());
288   out->Print(" */\n");
289   vars["name"] = GetPHPServiceClassname(service, class_suffix, is_server);
290   vars["extends"] = is_server ? "" : "extends \\Grpc\\BaseStub ";
291   out->Print(vars, "class $name$ $extends${\n\n");
292   out->Indent();
293   out->Indent();
294   if (!is_server) {
295     out->Print(
296         "/**\n * @param string $$hostname hostname\n"
297         " * @param array $$opts channel options\n"
298         " * @param \\Grpc\\Channel $$channel (optional) re-use channel object\n"
299         " */\n"
300         "public function __construct($$hostname, $$opts, "
301         "$$channel = null) {\n");
302     out->Indent();
303     out->Indent();
304     out->Print("parent::__construct($$hostname, $$opts, $$channel);\n");
305     out->Outdent();
306     out->Outdent();
307     out->Print("}\n\n");
308   }
309   for (int i = 0; i < service->method_count(); i++) {
310     if (is_server) {
311       PrintServerMethod(service->method(i), out);
312     } else {
313       PrintMethod(service->method(i), out);
314     }
315   }
316   if (is_server) {
317     PrintServerMethodDescriptors(service, out);
318   }
319   out->Outdent();
320   out->Outdent();
321   out->Print("}\n");
322 }
323 }  // namespace
324 
GenerateFile(const FileDescriptor * file,const ServiceDescriptor * service,const std::string & class_suffix,bool is_server)325 std::string GenerateFile(const FileDescriptor* file,
326                          const ServiceDescriptor* service,
327                          const std::string& class_suffix, bool is_server) {
328   std::string output;
329   {
330     StringOutputStream output_stream(&output);
331     Printer out(&output_stream, '$');
332 
333     out.Print("<?php\n");
334     out.Print("// GENERATED CODE -- DO NOT EDIT!\n\n");
335 
336     std::string leading_comments = GetPHPComments(file, "//");
337     if (!leading_comments.empty()) {
338       out.Print("// Original file comments:\n");
339       out.PrintRaw(leading_comments.c_str());
340     }
341 
342     map<std::string, std::string> vars;
343     std::string php_namespace = PackageName(file);
344     vars["package"] = php_namespace;
345     out.Print(vars, "namespace $package$;\n\n");
346 
347     PrintService(service, class_suffix, is_server, &out);
348   }
349   return output;
350 }
351 
352 }  // namespace grpc_php_generator
353