php_generator.cc 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. #include <google/protobuf/compiler/php/php_generator.h>
  31. #include <google/protobuf/compiler/code_generator.h>
  32. #include <google/protobuf/compiler/plugin.h>
  33. #include <google/protobuf/descriptor.h>
  34. #include <google/protobuf/descriptor.pb.h>
  35. #include <google/protobuf/io/printer.h>
  36. #include <google/protobuf/io/zero_copy_stream.h>
  37. #include <google/protobuf/stubs/strutil.h>
  38. #include <sstream>
  39. const std::string kDescriptorFile = "google/protobuf/descriptor.proto";
  40. const std::string kEmptyFile = "google/protobuf/empty.proto";
  41. const std::string kEmptyMetadataFile = "GPBMetadata/Google/Protobuf/GPBEmpty.php";
  42. const std::string kDescriptorMetadataFile =
  43. "GPBMetadata/Google/Protobuf/Internal/Descriptor.php";
  44. const std::string kDescriptorDirName = "Google/Protobuf/Internal";
  45. const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal";
  46. const char* const kReservedNames[] = {
  47. "abstract", "and", "array", "as", "break",
  48. "callable", "case", "catch", "class", "clone",
  49. "const", "continue", "declare", "default", "die",
  50. "do", "echo", "else", "elseif", "empty",
  51. "enddeclare", "endfor", "endforeach", "endif", "endswitch",
  52. "endwhile", "eval", "exit", "extends", "final",
  53. "for", "foreach", "function", "global", "goto",
  54. "if", "implements", "include", "include_once", "instanceof",
  55. "insteadof", "interface", "isset", "list", "namespace",
  56. "new", "or", "print", "private", "protected",
  57. "public", "require", "require_once", "return", "static",
  58. "switch", "throw", "trait", "try", "unset",
  59. "use", "var", "while", "xor", "int",
  60. "float", "bool", "string", "true", "false",
  61. "null", "void", "iterable"};
  62. const char* const kValidConstantNames[] = {
  63. "int", "float", "bool", "string", "true",
  64. "false", "null", "void", "iterable",
  65. };
  66. const int kReservedNamesSize = 73;
  67. const int kValidConstantNamesSize = 9;
  68. const int kFieldSetter = 1;
  69. const int kFieldGetter = 2;
  70. const int kFieldProperty = 3;
  71. namespace google {
  72. namespace protobuf {
  73. namespace compiler {
  74. namespace php {
  75. // Forward decls.
  76. std::string PhpName(const std::string& full_name, bool is_descriptor);
  77. std::string DefaultForField(FieldDescriptor* field);
  78. std::string IntToString(int32 value);
  79. std::string FilenameToClassname(const string& filename);
  80. std::string GeneratedMetadataFileName(const FileDescriptor* file,
  81. bool is_descriptor);
  82. std::string LabelForField(FieldDescriptor* field);
  83. std::string TypeName(FieldDescriptor* field);
  84. std::string UnderscoresToCamelCase(const string& name, bool cap_first_letter);
  85. std::string EscapeDollor(const string& to_escape);
  86. std::string BinaryToHex(const string& binary);
  87. void Indent(io::Printer* printer);
  88. void Outdent(io::Printer* printer);
  89. void GenerateMessageDocComment(io::Printer* printer, const Descriptor* message,
  90. int is_descriptor);
  91. void GenerateMessageConstructorDocComment(io::Printer* printer,
  92. const Descriptor* message,
  93. int is_descriptor);
  94. void GenerateFieldDocComment(io::Printer* printer, const FieldDescriptor* field,
  95. int is_descriptor, int function_type);
  96. void GenerateWrapperFieldGetterDocComment(io::Printer* printer,
  97. const FieldDescriptor* field);
  98. void GenerateWrapperFieldSetterDocComment(io::Printer* printer,
  99. const FieldDescriptor* field);
  100. void GenerateEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_,
  101. int is_descriptor);
  102. void GenerateEnumValueDocComment(io::Printer* printer,
  103. const EnumValueDescriptor* value);
  104. void GenerateServiceDocComment(io::Printer* printer,
  105. const ServiceDescriptor* service);
  106. void GenerateServiceMethodDocComment(io::Printer* printer,
  107. const MethodDescriptor* method);
  108. std::string ReservedNamePrefix(const string& classname,
  109. const FileDescriptor* file) {
  110. bool is_reserved = false;
  111. string lower = classname;
  112. transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
  113. for (int i = 0; i < kReservedNamesSize; i++) {
  114. if (lower == kReservedNames[i]) {
  115. is_reserved = true;
  116. break;
  117. }
  118. }
  119. if (is_reserved) {
  120. if (file->package() == "google.protobuf") {
  121. return "GPB";
  122. } else {
  123. return "PB";
  124. }
  125. }
  126. return "";
  127. }
  128. template <typename DescriptorType>
  129. std::string DescriptorFullName(const DescriptorType* desc, bool is_descriptor) {
  130. if (is_descriptor) {
  131. return StringReplace(desc->full_name(),
  132. "google.protobuf",
  133. "google.protobuf.internal", false);
  134. } else {
  135. return desc->full_name();
  136. }
  137. }
  138. template <typename DescriptorType>
  139. std::string ClassNamePrefix(const string& classname,
  140. const DescriptorType* desc) {
  141. const string& prefix = (desc->file()->options()).php_class_prefix();
  142. if (prefix != "") {
  143. return prefix;
  144. }
  145. return ReservedNamePrefix(classname, desc->file());
  146. }
  147. template <typename DescriptorType>
  148. std::string GeneratedClassNameImpl(const DescriptorType* desc) {
  149. std::string classname = ClassNamePrefix(desc->name(), desc) + desc->name();
  150. const Descriptor* containing = desc->containing_type();
  151. while (containing != NULL) {
  152. classname = ClassNamePrefix(containing->name(), desc) + containing->name()
  153. + '\\' + classname;
  154. containing = containing->containing_type();
  155. }
  156. return classname;
  157. }
  158. std::string GeneratedClassNameImpl(const ServiceDescriptor* desc) {
  159. std::string classname = desc->name();
  160. return ClassNamePrefix(classname, desc) + classname;
  161. }
  162. std::string GeneratedClassName(const Descriptor* desc) {
  163. return GeneratedClassNameImpl(desc);
  164. }
  165. std::string GeneratedClassName(const EnumDescriptor* desc) {
  166. return GeneratedClassNameImpl(desc);
  167. }
  168. std::string GeneratedClassName(const ServiceDescriptor* desc) {
  169. return GeneratedClassNameImpl(desc);
  170. }
  171. template <typename DescriptorType>
  172. std::string LegacyGeneratedClassName(const DescriptorType* desc) {
  173. std::string classname = desc->name();
  174. const Descriptor* containing = desc->containing_type();
  175. while (containing != NULL) {
  176. classname = containing->name() + '_' + classname;
  177. containing = containing->containing_type();
  178. }
  179. return ClassNamePrefix(classname, desc) + classname;
  180. }
  181. std::string ClassNamePrefix(const string& classname) {
  182. string lower = classname;
  183. transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
  184. for (int i = 0; i < kReservedNamesSize; i++) {
  185. if (lower == kReservedNames[i]) {
  186. return "PB";
  187. }
  188. }
  189. return "";
  190. }
  191. std::string ConstantNamePrefix(const string& classname) {
  192. bool is_reserved = false;
  193. string lower = classname;
  194. transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
  195. for (int i = 0; i < kReservedNamesSize; i++) {
  196. if (lower == kReservedNames[i]) {
  197. is_reserved = true;
  198. break;
  199. }
  200. }
  201. for (int i = 0; i < kValidConstantNamesSize; i++) {
  202. if (lower == kValidConstantNames[i]) {
  203. is_reserved = false;
  204. break;
  205. }
  206. }
  207. if (is_reserved) {
  208. return "PB";
  209. }
  210. return "";
  211. }
  212. template <typename DescriptorType>
  213. std::string RootPhpNamespace(const DescriptorType* desc, bool is_descriptor) {
  214. if (desc->file()->options().has_php_namespace()) {
  215. const string& php_namespace = desc->file()->options().php_namespace();
  216. if (php_namespace != "") {
  217. return php_namespace;
  218. }
  219. return "";
  220. }
  221. if (desc->file()->package() != "") {
  222. return PhpName(desc->file()->package(), is_descriptor);
  223. }
  224. return "";
  225. }
  226. template <typename DescriptorType>
  227. std::string FullClassName(const DescriptorType* desc, bool is_descriptor) {
  228. string classname = GeneratedClassNameImpl(desc);
  229. string php_namespace = RootPhpNamespace(desc, is_descriptor);
  230. if (php_namespace != "") {
  231. return php_namespace + "\\" + classname;
  232. }
  233. return classname;
  234. }
  235. template <typename DescriptorType>
  236. std::string LegacyFullClassName(const DescriptorType* desc, bool is_descriptor) {
  237. string classname = LegacyGeneratedClassName(desc);
  238. string php_namespace = RootPhpNamespace(desc, is_descriptor);
  239. if (php_namespace != "") {
  240. return php_namespace + "\\" + classname;
  241. }
  242. return classname;
  243. }
  244. std::string PhpName(const std::string& full_name, bool is_descriptor) {
  245. if (is_descriptor) {
  246. return kDescriptorPackageName;
  247. }
  248. std::string segment;
  249. std::string result;
  250. bool cap_next_letter = true;
  251. for (int i = 0; i < full_name.size(); i++) {
  252. if ('a' <= full_name[i] && full_name[i] <= 'z' && cap_next_letter) {
  253. segment += full_name[i] + ('A' - 'a');
  254. cap_next_letter = false;
  255. } else if (full_name[i] == '.') {
  256. result += ClassNamePrefix(segment) + segment + '\\';
  257. segment = "";
  258. cap_next_letter = true;
  259. } else {
  260. segment += full_name[i];
  261. cap_next_letter = false;
  262. }
  263. }
  264. result += ClassNamePrefix(segment) + segment;
  265. return result;
  266. }
  267. std::string DefaultForField(const FieldDescriptor* field) {
  268. switch (field->type()) {
  269. case FieldDescriptor::TYPE_INT32:
  270. case FieldDescriptor::TYPE_INT64:
  271. case FieldDescriptor::TYPE_UINT32:
  272. case FieldDescriptor::TYPE_UINT64:
  273. case FieldDescriptor::TYPE_SINT32:
  274. case FieldDescriptor::TYPE_SINT64:
  275. case FieldDescriptor::TYPE_FIXED32:
  276. case FieldDescriptor::TYPE_FIXED64:
  277. case FieldDescriptor::TYPE_SFIXED32:
  278. case FieldDescriptor::TYPE_SFIXED64:
  279. case FieldDescriptor::TYPE_ENUM: return "0";
  280. case FieldDescriptor::TYPE_DOUBLE:
  281. case FieldDescriptor::TYPE_FLOAT: return "0.0";
  282. case FieldDescriptor::TYPE_BOOL: return "false";
  283. case FieldDescriptor::TYPE_STRING:
  284. case FieldDescriptor::TYPE_BYTES: return "''";
  285. case FieldDescriptor::TYPE_MESSAGE:
  286. case FieldDescriptor::TYPE_GROUP: return "null";
  287. default: assert(false); return "";
  288. }
  289. }
  290. std::string GeneratedMetadataFileName(const FileDescriptor* file,
  291. bool is_descriptor) {
  292. const string& proto_file = file->name();
  293. int start_index = 0;
  294. int first_index = proto_file.find_first_of("/", start_index);
  295. std::string result = "";
  296. std::string segment = "";
  297. if (proto_file == kEmptyFile) {
  298. return kEmptyMetadataFile;
  299. }
  300. if (is_descriptor) {
  301. return kDescriptorMetadataFile;
  302. }
  303. // Append directory name.
  304. std::string file_no_suffix;
  305. int lastindex = proto_file.find_last_of(".");
  306. if (proto_file == kEmptyFile) {
  307. return kEmptyMetadataFile;
  308. } else {
  309. file_no_suffix = proto_file.substr(0, lastindex);
  310. }
  311. if (file->options().has_php_metadata_namespace()) {
  312. const string& php_metadata_namespace =
  313. file->options().php_metadata_namespace();
  314. if (php_metadata_namespace != "" && php_metadata_namespace != "\\") {
  315. result += php_metadata_namespace;
  316. std::replace(result.begin(), result.end(), '\\', '/');
  317. if (result.at(result.size() - 1) != '/') {
  318. result += "/";
  319. }
  320. }
  321. } else {
  322. result += "GPBMetadata/";
  323. while (first_index != string::npos) {
  324. segment = UnderscoresToCamelCase(
  325. file_no_suffix.substr(start_index, first_index - start_index), true);
  326. result += ReservedNamePrefix(segment, file) + segment + "/";
  327. start_index = first_index + 1;
  328. first_index = file_no_suffix.find_first_of("/", start_index);
  329. }
  330. }
  331. // Append file name.
  332. int file_name_start = file_no_suffix.find_last_of("/");
  333. if (file_name_start == string::npos) {
  334. file_name_start = 0;
  335. } else {
  336. file_name_start += 1;
  337. }
  338. segment = UnderscoresToCamelCase(
  339. file_no_suffix.substr(file_name_start, first_index - file_name_start), true);
  340. return result + ReservedNamePrefix(segment, file) + segment + ".php";
  341. }
  342. template <typename DescriptorType>
  343. std::string GeneratedClassFileName(const DescriptorType* desc,
  344. bool is_descriptor) {
  345. std::string result = FullClassName(desc, is_descriptor);
  346. for (int i = 0; i < result.size(); i++) {
  347. if (result[i] == '\\') {
  348. result[i] = '/';
  349. }
  350. }
  351. return result + ".php";
  352. }
  353. template <typename DescriptorType>
  354. std::string LegacyGeneratedClassFileName(const DescriptorType* desc,
  355. bool is_descriptor) {
  356. std::string result = LegacyFullClassName(desc, is_descriptor);
  357. for (int i = 0; i < result.size(); i++) {
  358. if (result[i] == '\\') {
  359. result[i] = '/';
  360. }
  361. }
  362. return result + ".php";
  363. }
  364. std::string GeneratedServiceFileName(const ServiceDescriptor* service,
  365. bool is_descriptor) {
  366. std::string result = FullClassName(service, is_descriptor) + "Interface";
  367. for (int i = 0; i < result.size(); i++) {
  368. if (result[i] == '\\') {
  369. result[i] = '/';
  370. }
  371. }
  372. return result + ".php";
  373. }
  374. std::string IntToString(int32 value) {
  375. std::ostringstream os;
  376. os << value;
  377. return os.str();
  378. }
  379. std::string LabelForField(const FieldDescriptor* field) {
  380. switch (field->label()) {
  381. case FieldDescriptor::LABEL_OPTIONAL: return "optional";
  382. case FieldDescriptor::LABEL_REQUIRED: return "required";
  383. case FieldDescriptor::LABEL_REPEATED: return "repeated";
  384. default: assert(false); return "";
  385. }
  386. }
  387. std::string TypeName(const FieldDescriptor* field) {
  388. switch (field->type()) {
  389. case FieldDescriptor::TYPE_INT32: return "int32";
  390. case FieldDescriptor::TYPE_INT64: return "int64";
  391. case FieldDescriptor::TYPE_UINT32: return "uint32";
  392. case FieldDescriptor::TYPE_UINT64: return "uint64";
  393. case FieldDescriptor::TYPE_SINT32: return "sint32";
  394. case FieldDescriptor::TYPE_SINT64: return "sint64";
  395. case FieldDescriptor::TYPE_FIXED32: return "fixed32";
  396. case FieldDescriptor::TYPE_FIXED64: return "fixed64";
  397. case FieldDescriptor::TYPE_SFIXED32: return "sfixed32";
  398. case FieldDescriptor::TYPE_SFIXED64: return "sfixed64";
  399. case FieldDescriptor::TYPE_DOUBLE: return "double";
  400. case FieldDescriptor::TYPE_FLOAT: return "float";
  401. case FieldDescriptor::TYPE_BOOL: return "bool";
  402. case FieldDescriptor::TYPE_ENUM: return "enum";
  403. case FieldDescriptor::TYPE_STRING: return "string";
  404. case FieldDescriptor::TYPE_BYTES: return "bytes";
  405. case FieldDescriptor::TYPE_MESSAGE: return "message";
  406. case FieldDescriptor::TYPE_GROUP: return "group";
  407. default: assert(false); return "";
  408. }
  409. }
  410. std::string PhpSetterTypeName(const FieldDescriptor* field, bool is_descriptor) {
  411. if (field->is_map()) {
  412. return "array|\\Google\\Protobuf\\Internal\\MapField";
  413. }
  414. string type;
  415. switch (field->type()) {
  416. case FieldDescriptor::TYPE_INT32:
  417. case FieldDescriptor::TYPE_UINT32:
  418. case FieldDescriptor::TYPE_SINT32:
  419. case FieldDescriptor::TYPE_FIXED32:
  420. case FieldDescriptor::TYPE_SFIXED32:
  421. case FieldDescriptor::TYPE_ENUM:
  422. type = "int";
  423. break;
  424. case FieldDescriptor::TYPE_INT64:
  425. case FieldDescriptor::TYPE_UINT64:
  426. case FieldDescriptor::TYPE_SINT64:
  427. case FieldDescriptor::TYPE_FIXED64:
  428. case FieldDescriptor::TYPE_SFIXED64:
  429. type = "int|string";
  430. break;
  431. case FieldDescriptor::TYPE_DOUBLE:
  432. case FieldDescriptor::TYPE_FLOAT:
  433. type = "float";
  434. break;
  435. case FieldDescriptor::TYPE_BOOL:
  436. type = "bool";
  437. break;
  438. case FieldDescriptor::TYPE_STRING:
  439. case FieldDescriptor::TYPE_BYTES:
  440. type = "string";
  441. break;
  442. case FieldDescriptor::TYPE_MESSAGE:
  443. type = "\\" + FullClassName(field->message_type(), is_descriptor);
  444. break;
  445. case FieldDescriptor::TYPE_GROUP:
  446. return "null";
  447. default: assert(false); return "";
  448. }
  449. if (field->is_repeated()) {
  450. // accommodate for edge case with multiple types.
  451. size_t start_pos = type.find("|");
  452. if (start_pos != std::string::npos) {
  453. type.replace(start_pos, 1, "[]|");
  454. }
  455. type += "[]|\\Google\\Protobuf\\Internal\\RepeatedField";
  456. }
  457. return type;
  458. }
  459. std::string PhpGetterTypeName(const FieldDescriptor* field, bool is_descriptor) {
  460. if (field->is_map()) {
  461. return "\\Google\\Protobuf\\Internal\\MapField";
  462. }
  463. if (field->is_repeated()) {
  464. return "\\Google\\Protobuf\\Internal\\RepeatedField";
  465. }
  466. switch (field->type()) {
  467. case FieldDescriptor::TYPE_INT32:
  468. case FieldDescriptor::TYPE_UINT32:
  469. case FieldDescriptor::TYPE_SINT32:
  470. case FieldDescriptor::TYPE_FIXED32:
  471. case FieldDescriptor::TYPE_SFIXED32:
  472. case FieldDescriptor::TYPE_ENUM: return "int";
  473. case FieldDescriptor::TYPE_INT64:
  474. case FieldDescriptor::TYPE_UINT64:
  475. case FieldDescriptor::TYPE_SINT64:
  476. case FieldDescriptor::TYPE_FIXED64:
  477. case FieldDescriptor::TYPE_SFIXED64: return "int|string";
  478. case FieldDescriptor::TYPE_DOUBLE:
  479. case FieldDescriptor::TYPE_FLOAT: return "float";
  480. case FieldDescriptor::TYPE_BOOL: return "bool";
  481. case FieldDescriptor::TYPE_STRING:
  482. case FieldDescriptor::TYPE_BYTES: return "string";
  483. case FieldDescriptor::TYPE_MESSAGE:
  484. return "\\" + FullClassName(field->message_type(), is_descriptor);
  485. case FieldDescriptor::TYPE_GROUP: return "null";
  486. default: assert(false); return "";
  487. }
  488. }
  489. std::string EnumOrMessageSuffix(
  490. const FieldDescriptor* field, bool is_descriptor) {
  491. if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  492. return ", '" + DescriptorFullName(field->message_type(), is_descriptor) + "'";
  493. }
  494. if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
  495. return ", '" + DescriptorFullName(field->enum_type(), is_descriptor) + "'";
  496. }
  497. return "";
  498. }
  499. // Converts a name to camel-case. If cap_first_letter is true, capitalize the
  500. // first letter.
  501. std::string UnderscoresToCamelCase(const string& input, bool cap_first_letter) {
  502. std::string result;
  503. for (int i = 0; i < input.size(); i++) {
  504. if ('a' <= input[i] && input[i] <= 'z') {
  505. if (cap_first_letter) {
  506. result += input[i] + ('A' - 'a');
  507. } else {
  508. result += input[i];
  509. }
  510. cap_first_letter = false;
  511. } else if ('A' <= input[i] && input[i] <= 'Z') {
  512. if (i == 0 && !cap_first_letter) {
  513. // Force first letter to lower-case unless explicitly told to
  514. // capitalize it.
  515. result += input[i] + ('a' - 'A');
  516. } else {
  517. // Capital letters after the first are left as-is.
  518. result += input[i];
  519. }
  520. cap_first_letter = false;
  521. } else if ('0' <= input[i] && input[i] <= '9') {
  522. result += input[i];
  523. cap_first_letter = true;
  524. } else {
  525. cap_first_letter = true;
  526. }
  527. }
  528. // Add a trailing "_" if the name should be altered.
  529. if (input[input.size() - 1] == '#') {
  530. result += '_';
  531. }
  532. return result;
  533. }
  534. std::string EscapeDollor(const string& to_escape) {
  535. return StringReplace(to_escape, "$", "\\$", true);
  536. }
  537. std::string BinaryToHex(const string& src) {
  538. string dest;
  539. size_t i;
  540. unsigned char symbol[16] = {
  541. '0', '1', '2', '3',
  542. '4', '5', '6', '7',
  543. '8', '9', 'a', 'b',
  544. 'c', 'd', 'e', 'f',
  545. };
  546. dest.resize(src.size() * 2);
  547. char* append_ptr = &dest[0];
  548. for (i = 0; i < src.size(); i++) {
  549. *append_ptr++ = symbol[(src[i] & 0xf0) >> 4];
  550. *append_ptr++ = symbol[src[i] & 0x0f];
  551. }
  552. return dest;
  553. }
  554. void Indent(io::Printer* printer) {
  555. printer->Indent();
  556. printer->Indent();
  557. }
  558. void Outdent(io::Printer* printer) {
  559. printer->Outdent();
  560. printer->Outdent();
  561. }
  562. void GenerateField(const FieldDescriptor* field, io::Printer* printer,
  563. bool is_descriptor) {
  564. if (field->is_repeated()) {
  565. GenerateFieldDocComment(printer, field, is_descriptor, kFieldProperty);
  566. printer->Print(
  567. "private $^name^;\n",
  568. "name", field->name());
  569. } else if (field->containing_oneof()) {
  570. // Oneof fields are handled by GenerateOneofField.
  571. return;
  572. } else {
  573. GenerateFieldDocComment(printer, field, is_descriptor, kFieldProperty);
  574. printer->Print(
  575. "private $^name^ = ^default^;\n",
  576. "name", field->name(),
  577. "default", DefaultForField(field));
  578. }
  579. if (is_descriptor) {
  580. printer->Print(
  581. "private $has_^name^ = false;\n",
  582. "name", field->name());
  583. }
  584. }
  585. void GenerateOneofField(const OneofDescriptor* oneof, io::Printer* printer) {
  586. // Oneof property needs to be protected in order to be accessed by parent
  587. // class in implementation.
  588. printer->Print(
  589. "protected $^name^;\n",
  590. "name", oneof->name());
  591. }
  592. void GenerateFieldAccessor(const FieldDescriptor* field, bool is_descriptor,
  593. io::Printer* printer) {
  594. const OneofDescriptor* oneof = field->containing_oneof();
  595. // Generate getter.
  596. if (oneof != NULL) {
  597. GenerateFieldDocComment(printer, field, is_descriptor, kFieldGetter);
  598. printer->Print(
  599. "public function get^camel_name^()\n"
  600. "{\n"
  601. " return $this->readOneof(^number^);\n"
  602. "}\n\n",
  603. "camel_name", UnderscoresToCamelCase(field->name(), true),
  604. "number", IntToString(field->number()));
  605. } else {
  606. GenerateFieldDocComment(printer, field, is_descriptor, kFieldGetter);
  607. printer->Print(
  608. "public function get^camel_name^()\n"
  609. "{\n"
  610. " return $this->^name^;\n"
  611. "}\n\n",
  612. "camel_name", UnderscoresToCamelCase(field->name(), true), "name",
  613. field->name());
  614. }
  615. // For wrapper types, generate an additional getXXXUnwrapped getter
  616. if (!field->is_map() &&
  617. !field->is_repeated() &&
  618. field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
  619. IsWrapperType(field)) {
  620. GenerateWrapperFieldGetterDocComment(printer, field);
  621. printer->Print(
  622. "public function get^camel_name^Unwrapped()\n"
  623. "{\n"
  624. " $wrapper = $this->get^camel_name^();\n"
  625. " return is_null($wrapper) ? null : $wrapper->getValue();\n"
  626. "}\n\n",
  627. "camel_name", UnderscoresToCamelCase(field->name(), true));
  628. }
  629. // Generate setter.
  630. GenerateFieldDocComment(printer, field, is_descriptor, kFieldSetter);
  631. printer->Print(
  632. "public function set^camel_name^($var)\n"
  633. "{\n",
  634. "camel_name", UnderscoresToCamelCase(field->name(), true));
  635. Indent(printer);
  636. // Type check.
  637. if (field->is_map()) {
  638. const Descriptor* map_entry = field->message_type();
  639. const FieldDescriptor* key = map_entry->FindFieldByName("key");
  640. const FieldDescriptor* value = map_entry->FindFieldByName("value");
  641. printer->Print(
  642. "$arr = GPBUtil::checkMapField($var, "
  643. "\\Google\\Protobuf\\Internal\\GPBType::^key_type^, "
  644. "\\Google\\Protobuf\\Internal\\GPBType::^value_type^",
  645. "key_type", ToUpper(key->type_name()),
  646. "value_type", ToUpper(value->type_name()));
  647. if (value->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  648. printer->Print(
  649. ", \\^class_name^);\n",
  650. "class_name",
  651. FullClassName(value->message_type(), is_descriptor) + "::class");
  652. } else if (value->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
  653. printer->Print(
  654. ", \\^class_name^);\n",
  655. "class_name",
  656. FullClassName(value->enum_type(), is_descriptor) + "::class");
  657. } else {
  658. printer->Print(");\n");
  659. }
  660. } else if (field->is_repeated()) {
  661. printer->Print(
  662. "$arr = GPBUtil::checkRepeatedField($var, "
  663. "\\Google\\Protobuf\\Internal\\GPBType::^type^",
  664. "type", ToUpper(field->type_name()));
  665. if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  666. printer->Print(
  667. ", \\^class_name^);\n",
  668. "class_name",
  669. FullClassName(field->message_type(), is_descriptor) + "::class");
  670. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
  671. printer->Print(
  672. ", \\^class_name^);\n",
  673. "class_name",
  674. FullClassName(field->enum_type(), is_descriptor) + "::class");
  675. } else {
  676. printer->Print(");\n");
  677. }
  678. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  679. printer->Print(
  680. "GPBUtil::checkMessage($var, \\^class_name^::class);\n",
  681. "class_name", LegacyFullClassName(field->message_type(), is_descriptor));
  682. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
  683. printer->Print(
  684. "GPBUtil::checkEnum($var, \\^class_name^::class);\n",
  685. "class_name", LegacyFullClassName(field->enum_type(), is_descriptor));
  686. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
  687. printer->Print(
  688. "GPBUtil::checkString($var, ^utf8^);\n",
  689. "utf8",
  690. field->type() == FieldDescriptor::TYPE_STRING ? "True": "False");
  691. } else {
  692. printer->Print(
  693. "GPBUtil::check^type^($var);\n",
  694. "type", UnderscoresToCamelCase(field->cpp_type_name(), true));
  695. }
  696. if (oneof != NULL) {
  697. printer->Print(
  698. "$this->writeOneof(^number^, $var);\n",
  699. "number", IntToString(field->number()));
  700. } else if (field->is_repeated()) {
  701. printer->Print(
  702. "$this->^name^ = $arr;\n",
  703. "name", field->name());
  704. } else {
  705. printer->Print(
  706. "$this->^name^ = $var;\n",
  707. "name", field->name());
  708. }
  709. // Set has bit for proto2 only.
  710. if (is_descriptor) {
  711. printer->Print(
  712. "$this->has_^field_name^ = true;\n",
  713. "field_name", field->name());
  714. }
  715. printer->Print("\nreturn $this;\n");
  716. Outdent(printer);
  717. printer->Print(
  718. "}\n\n");
  719. // For wrapper types, generate an additional setXXXValue getter
  720. if (!field->is_map() &&
  721. !field->is_repeated() &&
  722. field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
  723. IsWrapperType(field)) {
  724. GenerateWrapperFieldSetterDocComment(printer, field);
  725. printer->Print(
  726. "public function set^camel_name^Unwrapped($var)\n"
  727. "{\n"
  728. " $wrappedVar = is_null($var) ? null : new \\^wrapper_type^(['value' => $var]);\n"
  729. " return $this->set^camel_name^($wrappedVar);\n"
  730. "}\n\n",
  731. "camel_name", UnderscoresToCamelCase(field->name(), true),
  732. "wrapper_type", LegacyFullClassName(field->message_type(), is_descriptor));
  733. }
  734. // Generate has method for proto2 only.
  735. if (is_descriptor) {
  736. printer->Print(
  737. "public function has^camel_name^()\n"
  738. "{\n"
  739. " return $this->has_^field_name^;\n"
  740. "}\n\n",
  741. "camel_name", UnderscoresToCamelCase(field->name(), true),
  742. "field_name", field->name());
  743. }
  744. }
  745. void GenerateEnumToPool(const EnumDescriptor* en, io::Printer* printer) {
  746. printer->Print(
  747. "$pool->addEnum('^name^', "
  748. "\\Google\\Protobuf\\Internal\\^class_name^::class)\n",
  749. "name", DescriptorFullName(en, true),
  750. "class_name", en->name());
  751. Indent(printer);
  752. for (int i = 0; i < en->value_count(); i++) {
  753. const EnumValueDescriptor* value = en->value(i);
  754. printer->Print(
  755. "->value(\"^name^\", ^number^)\n",
  756. "name", ConstantNamePrefix(value->name()) + value->name(),
  757. "number", IntToString(value->number()));
  758. }
  759. printer->Print("->finalizeToPool();\n\n");
  760. Outdent(printer);
  761. }
  762. void GenerateServiceMethod(const MethodDescriptor* method,
  763. io::Printer* printer) {
  764. printer->Print(
  765. "public function ^camel_name^(\\^request_name^ $request);\n\n",
  766. "camel_name", UnderscoresToCamelCase(method->name(), false),
  767. "request_name", FullClassName(
  768. method->input_type(), false)
  769. );
  770. }
  771. void GenerateMessageToPool(const string& name_prefix, const Descriptor* message,
  772. io::Printer* printer) {
  773. // Don't generate MapEntry messages -- we use the PHP extension's native
  774. // support for map fields instead.
  775. if (message->options().map_entry()) {
  776. return;
  777. }
  778. string class_name = (name_prefix.empty() ? "" : name_prefix + "\\") +
  779. ReservedNamePrefix(message->name(), message->file()) + message->name();
  780. printer->Print(
  781. "$pool->addMessage('^message^', "
  782. "\\Google\\Protobuf\\Internal\\^class_name^::class)\n",
  783. "message", DescriptorFullName(message, true),
  784. "class_name", class_name);
  785. Indent(printer);
  786. for (int i = 0; i < message->field_count(); i++) {
  787. const FieldDescriptor* field = message->field(i);
  788. if (field->is_map()) {
  789. const FieldDescriptor* key =
  790. field->message_type()->FindFieldByName("key");
  791. const FieldDescriptor* val =
  792. field->message_type()->FindFieldByName("value");
  793. printer->Print(
  794. "->map('^field^', \\Google\\Protobuf\\Internal\\GPBType::^key^, "
  795. "\\Google\\Protobuf\\Internal\\GPBType::^value^, ^number^^other^)\n",
  796. "field", field->name(),
  797. "key", ToUpper(key->type_name()),
  798. "value", ToUpper(val->type_name()),
  799. "number", StrCat(field->number()),
  800. "other", EnumOrMessageSuffix(val, true));
  801. } else if (!field->containing_oneof()) {
  802. printer->Print(
  803. "->^label^('^field^', "
  804. "\\Google\\Protobuf\\Internal\\GPBType::^type^, ^number^^other^)\n",
  805. "field", field->name(),
  806. "label", LabelForField(field),
  807. "type", ToUpper(field->type_name()),
  808. "number", StrCat(field->number()),
  809. "other", EnumOrMessageSuffix(field, true));
  810. }
  811. }
  812. // oneofs.
  813. for (int i = 0; i < message->oneof_decl_count(); i++) {
  814. const OneofDescriptor* oneof = message->oneof_decl(i);
  815. printer->Print("->oneof(^name^)\n",
  816. "name", oneof->name());
  817. Indent(printer);
  818. for (int index = 0; index < oneof->field_count(); index++) {
  819. const FieldDescriptor* field = oneof->field(index);
  820. printer->Print(
  821. "->value('^field^', "
  822. "\\Google\\Protobuf\\Internal\\GPBType::^type^, ^number^^other^)\n",
  823. "field", field->name(),
  824. "type", ToUpper(field->type_name()),
  825. "number", StrCat(field->number()),
  826. "other", EnumOrMessageSuffix(field, true));
  827. }
  828. printer->Print("->finish()\n");
  829. Outdent(printer);
  830. }
  831. printer->Print(
  832. "->finalizeToPool();\n");
  833. Outdent(printer);
  834. printer->Print(
  835. "\n");
  836. for (int i = 0; i < message->nested_type_count(); i++) {
  837. GenerateMessageToPool(class_name, message->nested_type(i), printer);
  838. }
  839. for (int i = 0; i < message->enum_type_count(); i++) {
  840. GenerateEnumToPool(message->enum_type(i), printer);
  841. }
  842. }
  843. void GenerateAddFileToPool(const FileDescriptor* file, bool is_descriptor,
  844. io::Printer* printer) {
  845. printer->Print(
  846. "public static $is_initialized = false;\n\n"
  847. "public static function initOnce() {\n");
  848. Indent(printer);
  849. printer->Print(
  850. "$pool = \\Google\\Protobuf\\Internal\\"
  851. "DescriptorPool::getGeneratedPool();\n\n"
  852. "if (static::$is_initialized == true) {\n"
  853. " return;\n"
  854. "}\n");
  855. if (is_descriptor) {
  856. for (int i = 0; i < file->message_type_count(); i++) {
  857. GenerateMessageToPool("", file->message_type(i), printer);
  858. }
  859. for (int i = 0; i < file->enum_type_count(); i++) {
  860. GenerateEnumToPool(file->enum_type(i), printer);
  861. }
  862. printer->Print(
  863. "$pool->finish();\n");
  864. } else {
  865. for (int i = 0; i < file->dependency_count(); i++) {
  866. const std::string& name = file->dependency(i)->name();
  867. // Currently, descriptor.proto is not ready for external usage. Skip to
  868. // import it for now, so that its dependencies can still work as long as
  869. // they don't use protos defined in descriptor.proto.
  870. if (name == kDescriptorFile) {
  871. continue;
  872. }
  873. std::string dependency_filename =
  874. GeneratedMetadataFileName(file->dependency(i), is_descriptor);
  875. printer->Print(
  876. "\\^name^::initOnce();\n",
  877. "name", FilenameToClassname(dependency_filename));
  878. }
  879. // Add messages and enums to descriptor pool.
  880. FileDescriptorSet files;
  881. FileDescriptorProto* file_proto = files.add_file();
  882. file->CopyTo(file_proto);
  883. // Filter out descriptor.proto as it cannot be depended on for now.
  884. RepeatedPtrField<string>* dependency = file_proto->mutable_dependency();
  885. for (RepeatedPtrField<string>::iterator it = dependency->begin();
  886. it != dependency->end(); ++it) {
  887. if (*it != kDescriptorFile) {
  888. dependency->erase(it);
  889. break;
  890. }
  891. }
  892. // Filter out all extensions, since we do not support extension yet.
  893. file_proto->clear_extension();
  894. RepeatedPtrField<DescriptorProto>* message_type =
  895. file_proto->mutable_message_type();
  896. for (RepeatedPtrField<DescriptorProto>::iterator it = message_type->begin();
  897. it != message_type->end(); ++it) {
  898. it->clear_extension();
  899. }
  900. string files_data;
  901. files.SerializeToString(&files_data);
  902. printer->Print("$pool->internalAddGeneratedFile(hex2bin(\n");
  903. Indent(printer);
  904. // Only write 30 bytes per line.
  905. static const int kBytesPerLine = 30;
  906. for (int i = 0; i < files_data.size(); i += kBytesPerLine) {
  907. printer->Print(
  908. "\"^data^\"^dot^\n",
  909. "data", BinaryToHex(files_data.substr(i, kBytesPerLine)),
  910. "dot", i + kBytesPerLine < files_data.size() ? " ." : "");
  911. }
  912. Outdent(printer);
  913. printer->Print(
  914. "), true);\n\n");
  915. }
  916. printer->Print(
  917. "static::$is_initialized = true;\n");
  918. Outdent(printer);
  919. printer->Print("}\n");
  920. }
  921. void GenerateUseDeclaration(bool is_descriptor, io::Printer* printer) {
  922. if (!is_descriptor) {
  923. printer->Print(
  924. "use Google\\Protobuf\\Internal\\GPBType;\n"
  925. "use Google\\Protobuf\\Internal\\RepeatedField;\n"
  926. "use Google\\Protobuf\\Internal\\GPBUtil;\n\n");
  927. } else {
  928. printer->Print(
  929. "use Google\\Protobuf\\Internal\\GPBType;\n"
  930. "use Google\\Protobuf\\Internal\\GPBWire;\n"
  931. "use Google\\Protobuf\\Internal\\RepeatedField;\n"
  932. "use Google\\Protobuf\\Internal\\InputStream;\n"
  933. "use Google\\Protobuf\\Internal\\GPBUtil;\n\n");
  934. }
  935. }
  936. void GenerateHead(const FileDescriptor* file, io::Printer* printer) {
  937. printer->Print(
  938. "<?php\n"
  939. "# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
  940. "# source: ^filename^\n"
  941. "\n",
  942. "filename", file->name());
  943. }
  944. std::string FilenameToClassname(const string& filename) {
  945. int lastindex = filename.find_last_of(".");
  946. std::string result = filename.substr(0, lastindex);
  947. for (int i = 0; i < result.size(); i++) {
  948. if (result[i] == '/') {
  949. result[i] = '\\';
  950. }
  951. }
  952. return result;
  953. }
  954. void GenerateMetadataFile(const FileDescriptor* file,
  955. bool is_descriptor,
  956. GeneratorContext* generator_context) {
  957. std::string filename = GeneratedMetadataFileName(file, is_descriptor);
  958. std::unique_ptr<io::ZeroCopyOutputStream> output(
  959. generator_context->Open(filename));
  960. io::Printer printer(output.get(), '^');
  961. GenerateHead(file, &printer);
  962. std::string fullname = FilenameToClassname(filename);
  963. int lastindex = fullname.find_last_of("\\");
  964. if (lastindex != string::npos) {
  965. printer.Print(
  966. "namespace ^name^;\n\n",
  967. "name", fullname.substr(0, lastindex));
  968. printer.Print(
  969. "class ^name^\n"
  970. "{\n",
  971. "name", fullname.substr(lastindex + 1));
  972. } else {
  973. printer.Print(
  974. "class ^name^\n"
  975. "{\n",
  976. "name", fullname);
  977. }
  978. Indent(&printer);
  979. GenerateAddFileToPool(file, is_descriptor, &printer);
  980. Outdent(&printer);
  981. printer.Print("}\n\n");
  982. }
  983. template <typename DescriptorType>
  984. void LegacyGenerateClassFile(const FileDescriptor* file, const DescriptorType* desc,
  985. bool is_descriptor,
  986. GeneratorContext* generator_context) {
  987. std::string filename = LegacyGeneratedClassFileName(desc, is_descriptor);
  988. std::unique_ptr<io::ZeroCopyOutputStream> output(
  989. generator_context->Open(filename));
  990. io::Printer printer(output.get(), '^');
  991. GenerateHead(file, &printer);
  992. std::string php_namespace = RootPhpNamespace(desc, is_descriptor);
  993. if (php_namespace != "") {
  994. printer.Print(
  995. "namespace ^name^;\n\n",
  996. "name", php_namespace);
  997. }
  998. std::string newname = FullClassName(desc, is_descriptor);
  999. printer.Print("if (false) {\n");
  1000. Indent(&printer);
  1001. printer.Print("/**\n");
  1002. printer.Print(" * This class is deprecated. Use ^new^ instead.\n",
  1003. "new", newname);
  1004. printer.Print(" * @deprecated\n");
  1005. printer.Print(" */\n");
  1006. printer.Print("class ^old^ {}\n",
  1007. "old", LegacyGeneratedClassName(desc));
  1008. Outdent(&printer);
  1009. printer.Print("}\n");
  1010. printer.Print("class_exists(^new^::class);\n",
  1011. "new", GeneratedClassNameImpl(desc));
  1012. printer.Print("@trigger_error('^old^ is deprecated and will be removed in "
  1013. "the next major release. Use ^fullname^ instead', E_USER_DEPRECATED);\n\n",
  1014. "old", LegacyFullClassName(desc, is_descriptor),
  1015. "fullname", newname);
  1016. }
  1017. void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en,
  1018. bool is_descriptor, GeneratorContext* generator_context) {
  1019. std::string filename = GeneratedClassFileName(en, is_descriptor);
  1020. std::unique_ptr<io::ZeroCopyOutputStream> output(
  1021. generator_context->Open(filename));
  1022. io::Printer printer(output.get(), '^');
  1023. GenerateHead(file, &printer);
  1024. std::string fullname = FilenameToClassname(filename);
  1025. int lastindex = fullname.find_last_of("\\");
  1026. if (lastindex != string::npos) {
  1027. printer.Print(
  1028. "namespace ^name^;\n\n",
  1029. "name", fullname.substr(0, lastindex));
  1030. // We only need this 'use' statement if the enum has a namespace.
  1031. // Otherwise, we get a warning that the use statement has no effect.
  1032. printer.Print("use UnexpectedValueException;\n\n");
  1033. }
  1034. GenerateEnumDocComment(&printer, en, is_descriptor);
  1035. if (lastindex != string::npos) {
  1036. fullname = fullname.substr(lastindex + 1);
  1037. }
  1038. printer.Print(
  1039. "class ^name^\n"
  1040. "{\n",
  1041. "name", fullname);
  1042. Indent(&printer);
  1043. for (int i = 0; i < en->value_count(); i++) {
  1044. const EnumValueDescriptor* value = en->value(i);
  1045. GenerateEnumValueDocComment(&printer, value);
  1046. printer.Print("const ^name^ = ^number^;\n",
  1047. "name", ConstantNamePrefix(value->name()) + value->name(),
  1048. "number", IntToString(value->number()));
  1049. }
  1050. printer.Print("\nprivate static $valueToName = [\n");
  1051. Indent(&printer);
  1052. for (int i = 0; i < en->value_count(); i++) {
  1053. const EnumValueDescriptor* value = en->value(i);
  1054. printer.Print("self::^name^ => '^name^',\n",
  1055. "name", ConstantNamePrefix(value->name()) + value->name());
  1056. }
  1057. Outdent(&printer);
  1058. printer.Print("];\n");
  1059. printer.Print(
  1060. "\npublic static function name($value)\n"
  1061. "{\n");
  1062. Indent(&printer);
  1063. printer.Print("if (!isset(self::$valueToName[$value])) {\n");
  1064. Indent(&printer);
  1065. printer.Print("throw new UnexpectedValueException(sprintf(\n");
  1066. Indent(&printer);
  1067. Indent(&printer);
  1068. printer.Print("'Enum %s has no name defined for value %s', __CLASS__, $value));\n");
  1069. Outdent(&printer);
  1070. Outdent(&printer);
  1071. Outdent(&printer);
  1072. printer.Print("}\n"
  1073. "return self::$valueToName[$value];\n");
  1074. Outdent(&printer);
  1075. printer.Print("}\n\n");
  1076. printer.Print(
  1077. "\npublic static function value($name)\n"
  1078. "{\n");
  1079. Indent(&printer);
  1080. printer.Print("$const = __CLASS__ . '::' . strtoupper($name);\n"
  1081. "if (!defined($const)) {\n");
  1082. Indent(&printer);
  1083. printer.Print("throw new UnexpectedValueException(sprintf(\n");
  1084. Indent(&printer);
  1085. Indent(&printer);
  1086. printer.Print("'Enum %s has no value defined for name %s', __CLASS__, $name));\n");
  1087. Outdent(&printer);
  1088. Outdent(&printer);
  1089. Outdent(&printer);
  1090. printer.Print("}\n"
  1091. "return constant($const);\n");
  1092. Outdent(&printer);
  1093. printer.Print("}\n");
  1094. Outdent(&printer);
  1095. printer.Print("}\n\n");
  1096. // write legacy file for backwards compatiblity with nested messages and enums
  1097. if (en->containing_type() != NULL) {
  1098. printer.Print(
  1099. "// Adding a class alias for backwards compatibility with the previous class name.\n");
  1100. printer.Print(
  1101. "class_alias(^new^::class, \\^old^::class);\n\n",
  1102. "new", fullname,
  1103. "old", LegacyFullClassName(en, is_descriptor));
  1104. LegacyGenerateClassFile(file, en, is_descriptor, generator_context);
  1105. }
  1106. }
  1107. void GenerateMessageFile(const FileDescriptor* file, const Descriptor* message,
  1108. bool is_descriptor,
  1109. GeneratorContext* generator_context) {
  1110. // Don't generate MapEntry messages -- we use the PHP extension's native
  1111. // support for map fields instead.
  1112. if (message->options().map_entry()) {
  1113. return;
  1114. }
  1115. std::string filename = GeneratedClassFileName(message, is_descriptor);
  1116. std::unique_ptr<io::ZeroCopyOutputStream> output(
  1117. generator_context->Open(filename));
  1118. io::Printer printer(output.get(), '^');
  1119. GenerateHead(file, &printer);
  1120. std::string fullname = FilenameToClassname(filename);
  1121. int lastindex = fullname.find_last_of("\\");
  1122. if (lastindex != string::npos) {
  1123. printer.Print(
  1124. "namespace ^name^;\n\n",
  1125. "name", fullname.substr(0, lastindex));
  1126. }
  1127. GenerateUseDeclaration(is_descriptor, &printer);
  1128. GenerateMessageDocComment(&printer, message, is_descriptor);
  1129. if (lastindex != string::npos) {
  1130. fullname = fullname.substr(lastindex + 1);
  1131. }
  1132. printer.Print(
  1133. "final class ^name^ extends \\Google\\Protobuf\\Internal\\Message\n"
  1134. "{\n",
  1135. "name", fullname);
  1136. Indent(&printer);
  1137. // Field and oneof definitions.
  1138. for (int i = 0; i < message->field_count(); i++) {
  1139. const FieldDescriptor* field = message->field(i);
  1140. GenerateField(field, &printer, is_descriptor);
  1141. }
  1142. for (int i = 0; i < message->oneof_decl_count(); i++) {
  1143. const OneofDescriptor* oneof = message->oneof_decl(i);
  1144. GenerateOneofField(oneof, &printer);
  1145. }
  1146. printer.Print("\n");
  1147. GenerateMessageConstructorDocComment(&printer, message, is_descriptor);
  1148. printer.Print(
  1149. "public function __construct($data = NULL) {\n");
  1150. Indent(&printer);
  1151. std::string metadata_filename =
  1152. GeneratedMetadataFileName(file, is_descriptor);
  1153. std::string metadata_fullname = FilenameToClassname(metadata_filename);
  1154. printer.Print(
  1155. "\\^fullname^::initOnce();\n"
  1156. "parent::__construct($data);\n",
  1157. "fullname", metadata_fullname);
  1158. Outdent(&printer);
  1159. printer.Print("}\n\n");
  1160. // Field and oneof accessors.
  1161. for (int i = 0; i < message->field_count(); i++) {
  1162. const FieldDescriptor* field = message->field(i);
  1163. GenerateFieldAccessor(field, is_descriptor, &printer);
  1164. }
  1165. for (int i = 0; i < message->oneof_decl_count(); i++) {
  1166. const OneofDescriptor* oneof = message->oneof_decl(i);
  1167. printer.Print(
  1168. "/**\n"
  1169. " * @return string\n"
  1170. " */\n"
  1171. "public function get^camel_name^()\n"
  1172. "{\n"
  1173. " return $this->whichOneof(\"^name^\");\n"
  1174. "}\n\n",
  1175. "camel_name", UnderscoresToCamelCase(oneof->name(), true), "name",
  1176. oneof->name());
  1177. }
  1178. Outdent(&printer);
  1179. printer.Print("}\n\n");
  1180. // write legacy file for backwards compatiblity with nested messages and enums
  1181. if (message->containing_type() != NULL) {
  1182. printer.Print(
  1183. "// Adding a class alias for backwards compatibility with the previous class name.\n");
  1184. printer.Print(
  1185. "class_alias(^new^::class, \\^old^::class);\n\n",
  1186. "new", fullname,
  1187. "old", LegacyFullClassName(message, is_descriptor));
  1188. LegacyGenerateClassFile(file, message, is_descriptor, generator_context);
  1189. }
  1190. // Nested messages and enums.
  1191. for (int i = 0; i < message->nested_type_count(); i++) {
  1192. GenerateMessageFile(file, message->nested_type(i), is_descriptor,
  1193. generator_context);
  1194. }
  1195. for (int i = 0; i < message->enum_type_count(); i++) {
  1196. GenerateEnumFile(file, message->enum_type(i), is_descriptor,
  1197. generator_context);
  1198. }
  1199. }
  1200. void GenerateServiceFile(const FileDescriptor* file,
  1201. const ServiceDescriptor* service, bool is_descriptor,
  1202. GeneratorContext* generator_context) {
  1203. std::string filename = GeneratedServiceFileName(service, is_descriptor);
  1204. std::unique_ptr<io::ZeroCopyOutputStream> output(
  1205. generator_context->Open(filename));
  1206. io::Printer printer(output.get(), '^');
  1207. GenerateHead(file, &printer);
  1208. std::string fullname = FilenameToClassname(filename);
  1209. int lastindex = fullname.find_last_of("\\");
  1210. if (!file->options().php_namespace().empty() ||
  1211. (!file->options().has_php_namespace() && !file->package().empty()) ||
  1212. lastindex != string::npos) {
  1213. printer.Print(
  1214. "namespace ^name^;\n\n",
  1215. "name", fullname.substr(0, lastindex));
  1216. }
  1217. GenerateServiceDocComment(&printer, service);
  1218. if (lastindex != string::npos) {
  1219. printer.Print(
  1220. "interface ^name^\n"
  1221. "{\n",
  1222. "name", fullname.substr(lastindex + 1));
  1223. } else {
  1224. printer.Print(
  1225. "interface ^name^\n"
  1226. "{\n",
  1227. "name", fullname);
  1228. }
  1229. Indent(&printer);
  1230. for (int i = 0; i < service->method_count(); i++) {
  1231. const MethodDescriptor* method = service->method(i);
  1232. GenerateServiceMethodDocComment(&printer, method);
  1233. GenerateServiceMethod(method, &printer);
  1234. }
  1235. Outdent(&printer);
  1236. printer.Print("}\n\n");
  1237. }
  1238. void GenerateFile(const FileDescriptor* file, bool is_descriptor,
  1239. GeneratorContext* generator_context) {
  1240. GenerateMetadataFile(file, is_descriptor, generator_context);
  1241. for (int i = 0; i < file->message_type_count(); i++) {
  1242. GenerateMessageFile(file, file->message_type(i), is_descriptor,
  1243. generator_context);
  1244. }
  1245. for (int i = 0; i < file->enum_type_count(); i++) {
  1246. GenerateEnumFile(file, file->enum_type(i), is_descriptor,
  1247. generator_context);
  1248. }
  1249. if (file->options().php_generic_services()) {
  1250. for (int i = 0; i < file->service_count(); i++) {
  1251. GenerateServiceFile(file, file->service(i), is_descriptor,
  1252. generator_context);
  1253. }
  1254. }
  1255. }
  1256. static string EscapePhpdoc(const string& input) {
  1257. string result;
  1258. result.reserve(input.size() * 2);
  1259. char prev = '*';
  1260. for (string::size_type i = 0; i < input.size(); i++) {
  1261. char c = input[i];
  1262. switch (c) {
  1263. case '*':
  1264. // Avoid "/*".
  1265. if (prev == '/') {
  1266. result.append("&#42;");
  1267. } else {
  1268. result.push_back(c);
  1269. }
  1270. break;
  1271. case '/':
  1272. // Avoid "*/".
  1273. if (prev == '*') {
  1274. result.append("&#47;");
  1275. } else {
  1276. result.push_back(c);
  1277. }
  1278. break;
  1279. case '@':
  1280. // '@' starts phpdoc tags including the @deprecated tag, which will
  1281. // cause a compile-time error if inserted before a declaration that
  1282. // does not have a corresponding @Deprecated annotation.
  1283. result.append("&#64;");
  1284. break;
  1285. default:
  1286. result.push_back(c);
  1287. break;
  1288. }
  1289. prev = c;
  1290. }
  1291. return result;
  1292. }
  1293. static void GenerateDocCommentBodyForLocation(
  1294. io::Printer* printer, const SourceLocation& location, bool trailingNewline,
  1295. int indentCount) {
  1296. string comments = location.leading_comments.empty() ?
  1297. location.trailing_comments : location.leading_comments;
  1298. if (!comments.empty()) {
  1299. // TODO(teboring): Ideally we should parse the comment text as Markdown and
  1300. // write it back as HTML, but this requires a Markdown parser. For now
  1301. // we just use the proto comments unchanged.
  1302. // If the comment itself contains block comment start or end markers,
  1303. // HTML-escape them so that they don't accidentally close the doc comment.
  1304. comments = EscapePhpdoc(comments);
  1305. std::vector<string> lines = Split(comments, "\n");
  1306. while (!lines.empty() && lines.back().empty()) {
  1307. lines.pop_back();
  1308. }
  1309. for (int i = 0; i < lines.size(); i++) {
  1310. // Most lines should start with a space. Watch out for lines that start
  1311. // with a /, since putting that right after the leading asterisk will
  1312. // close the comment.
  1313. if (indentCount == 0 && !lines[i].empty() && lines[i][0] == '/') {
  1314. printer->Print(" * ^line^\n", "line", lines[i]);
  1315. } else {
  1316. std::string indent = std::string(indentCount, ' ');
  1317. printer->Print(" *^ind^^line^\n", "ind", indent, "line", lines[i]);
  1318. }
  1319. }
  1320. if (trailingNewline) {
  1321. printer->Print(" *\n");
  1322. }
  1323. }
  1324. }
  1325. template <typename DescriptorType>
  1326. static void GenerateDocCommentBody(
  1327. io::Printer* printer, const DescriptorType* descriptor) {
  1328. SourceLocation location;
  1329. if (descriptor->GetSourceLocation(&location)) {
  1330. GenerateDocCommentBodyForLocation(printer, location, true, 0);
  1331. }
  1332. }
  1333. static string FirstLineOf(const string& value) {
  1334. string result = value;
  1335. string::size_type pos = result.find_first_of('\n');
  1336. if (pos != string::npos) {
  1337. result.erase(pos);
  1338. }
  1339. return result;
  1340. }
  1341. void GenerateMessageDocComment(io::Printer* printer,
  1342. const Descriptor* message, int is_descriptor) {
  1343. printer->Print("/**\n");
  1344. GenerateDocCommentBody(printer, message);
  1345. printer->Print(
  1346. " * Generated from protobuf message <code>^messagename^</code>\n"
  1347. " */\n",
  1348. "fullname", EscapePhpdoc(FullClassName(message, is_descriptor)),
  1349. "messagename", EscapePhpdoc(message->full_name()));
  1350. }
  1351. void GenerateMessageConstructorDocComment(io::Printer* printer,
  1352. const Descriptor* message,
  1353. int is_descriptor) {
  1354. // In theory we should have slightly different comments for setters, getters,
  1355. // etc., but in practice everyone already knows the difference between these
  1356. // so it's redundant information.
  1357. // We start the comment with the main body based on the comments from the
  1358. // .proto file (if present). We then end with the field declaration, e.g.:
  1359. // optional string foo = 5;
  1360. // If the field is a group, the debug string might end with {.
  1361. printer->Print("/**\n");
  1362. printer->Print(" * Constructor.\n");
  1363. printer->Print(" *\n");
  1364. printer->Print(" * @param array $data {\n");
  1365. printer->Print(" * Optional. Data for populating the Message object.\n");
  1366. printer->Print(" *\n");
  1367. for (int i = 0; i < message->field_count(); i++) {
  1368. const FieldDescriptor* field = message->field(i);
  1369. printer->Print(" * @type ^php_type^ $^var^\n",
  1370. "php_type", PhpSetterTypeName(field, is_descriptor),
  1371. "var", field->name());
  1372. SourceLocation location;
  1373. if (field->GetSourceLocation(&location)) {
  1374. GenerateDocCommentBodyForLocation(printer, location, false, 10);
  1375. }
  1376. }
  1377. printer->Print(" * }\n");
  1378. printer->Print(" */\n");
  1379. }
  1380. void GenerateServiceDocComment(io::Printer* printer,
  1381. const ServiceDescriptor* service) {
  1382. printer->Print("/**\n");
  1383. GenerateDocCommentBody(printer, service);
  1384. printer->Print(
  1385. " * Protobuf type <code>^fullname^</code>\n"
  1386. " */\n",
  1387. "fullname", EscapePhpdoc(service->full_name()));
  1388. }
  1389. void GenerateFieldDocComment(io::Printer* printer, const FieldDescriptor* field,
  1390. int is_descriptor, int function_type) {
  1391. // In theory we should have slightly different comments for setters, getters,
  1392. // etc., but in practice everyone already knows the difference between these
  1393. // so it's redundant information.
  1394. // We start the comment with the main body based on the comments from the
  1395. // .proto file (if present). We then end with the field declaration, e.g.:
  1396. // optional string foo = 5;
  1397. // If the field is a group, the debug string might end with {.
  1398. printer->Print("/**\n");
  1399. GenerateDocCommentBody(printer, field);
  1400. printer->Print(
  1401. " * Generated from protobuf field <code>^def^</code>\n",
  1402. "def", EscapePhpdoc(FirstLineOf(field->DebugString())));
  1403. if (function_type == kFieldSetter) {
  1404. printer->Print(" * @param ^php_type^ $var\n",
  1405. "php_type", PhpSetterTypeName(field, is_descriptor));
  1406. printer->Print(" * @return $this\n");
  1407. } else if (function_type == kFieldGetter) {
  1408. printer->Print(" * @return ^php_type^\n",
  1409. "php_type", PhpGetterTypeName(field, is_descriptor));
  1410. }
  1411. printer->Print(" */\n");
  1412. }
  1413. void GenerateWrapperFieldGetterDocComment(io::Printer* printer, const FieldDescriptor* field) {
  1414. // Generate a doc comment for the special getXXXValue methods that are
  1415. // generated for wrapper types.
  1416. const FieldDescriptor* primitiveField = field->message_type()->FindFieldByName("value");
  1417. printer->Print("/**\n");
  1418. printer->Print(
  1419. " * Returns the unboxed value from <code>get^camel_name^()</code>\n\n",
  1420. "camel_name", UnderscoresToCamelCase(field->name(), true));
  1421. GenerateDocCommentBody(printer, field);
  1422. printer->Print(
  1423. " * Generated from protobuf field <code>^def^</code>\n",
  1424. "def", EscapePhpdoc(FirstLineOf(field->DebugString())));
  1425. printer->Print(" * @return ^php_type^|null\n",
  1426. "php_type", PhpGetterTypeName(primitiveField, false));
  1427. printer->Print(" */\n");
  1428. }
  1429. void GenerateWrapperFieldSetterDocComment(io::Printer* printer, const FieldDescriptor* field) {
  1430. // Generate a doc comment for the special setXXXValue methods that are
  1431. // generated for wrapper types.
  1432. const FieldDescriptor* primitiveField = field->message_type()->FindFieldByName("value");
  1433. printer->Print("/**\n");
  1434. printer->Print(
  1435. " * Sets the field by wrapping a primitive type in a ^message_name^ object.\n\n",
  1436. "message_name", LegacyFullClassName(field->message_type(), false));
  1437. GenerateDocCommentBody(printer, field);
  1438. printer->Print(
  1439. " * Generated from protobuf field <code>^def^</code>\n",
  1440. "def", EscapePhpdoc(FirstLineOf(field->DebugString())));
  1441. printer->Print(" * @param ^php_type^|null $var\n",
  1442. "php_type", PhpSetterTypeName(primitiveField, false));
  1443. printer->Print(" * @return $this\n");
  1444. printer->Print(" */\n");
  1445. }
  1446. void GenerateEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_,
  1447. int is_descriptor) {
  1448. printer->Print("/**\n");
  1449. GenerateDocCommentBody(printer, enum_);
  1450. printer->Print(
  1451. " * Protobuf type <code>^fullname^</code>\n"
  1452. " */\n",
  1453. "fullname", EscapePhpdoc(enum_->full_name()));
  1454. }
  1455. void GenerateEnumValueDocComment(io::Printer* printer,
  1456. const EnumValueDescriptor* value) {
  1457. printer->Print("/**\n");
  1458. GenerateDocCommentBody(printer, value);
  1459. printer->Print(
  1460. " * Generated from protobuf enum <code>^def^</code>\n"
  1461. " */\n",
  1462. "def", EscapePhpdoc(FirstLineOf(value->DebugString())));
  1463. }
  1464. void GenerateServiceMethodDocComment(io::Printer* printer,
  1465. const MethodDescriptor* method) {
  1466. printer->Print("/**\n");
  1467. GenerateDocCommentBody(printer, method);
  1468. printer->Print(
  1469. " * Method <code>^method_name^</code>\n"
  1470. " *\n",
  1471. "method_name", EscapePhpdoc(UnderscoresToCamelCase(method->name(), false)));
  1472. printer->Print(
  1473. " * @param \\^input_type^ $request\n",
  1474. "input_type", EscapePhpdoc(FullClassName(method->input_type(), false)));
  1475. printer->Print(
  1476. " * @return \\^return_type^\n"
  1477. " */\n",
  1478. "return_type", EscapePhpdoc(FullClassName(method->output_type(), false)));
  1479. }
  1480. bool Generator::Generate(const FileDescriptor* file, const string& parameter,
  1481. GeneratorContext* generator_context,
  1482. string* error) const {
  1483. bool is_descriptor = parameter == "internal";
  1484. if (is_descriptor && file->name() != kDescriptorFile) {
  1485. *error =
  1486. "Can only generate PHP code for google/protobuf/descriptor.proto.\n";
  1487. return false;
  1488. }
  1489. if (!is_descriptor && file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
  1490. *error =
  1491. "Can only generate PHP code for proto3 .proto files.\n"
  1492. "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n";
  1493. return false;
  1494. }
  1495. GenerateFile(file, is_descriptor, generator_context);
  1496. return true;
  1497. }
  1498. } // namespace php
  1499. } // namespace compiler
  1500. } // namespace protobuf
  1501. } // namespace google