1/*
2* Copyright 2014 Google Inc. All rights reserved.
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8*     http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17// independent from idl_parser, since this code is not needed for most clients
18
19#include <string>
20
21#include "flatbuffers/flatbuffers.h"
22#include "flatbuffers/idl.h"
23#include "flatbuffers/util.h"
24#include "flatbuffers/code_generators.h"
25
26namespace flatbuffers {
27namespace php {
28    // Hardcode spaces per indentation.
29    const std::string Indent = "    ";
30    class PhpGenerator : public BaseGenerator {
31     public:
32      PhpGenerator(const Parser &parser, const std::string &path,
33                   const std::string &file_name)
34          : BaseGenerator(parser, path, file_name, "\\", "\\"){};
35      bool generate() {
36        if (!generateEnums()) return false;
37        if (!generateStructs()) return false;
38        return true;
39      }
40
41     private:
42      bool generateEnums() {
43        for (auto it = parser_.enums_.vec.begin();
44             it != parser_.enums_.vec.end(); ++it) {
45          auto &enum_def = **it;
46          std::string enumcode;
47          GenEnum(enum_def, &enumcode);
48          if (!SaveType(enum_def, enumcode, false)) return false;
49        }
50        return true;
51      }
52
53      bool generateStructs() {
54        for (auto it = parser_.structs_.vec.begin();
55             it != parser_.structs_.vec.end(); ++it) {
56          auto &struct_def = **it;
57          std::string declcode;
58          GenStruct(struct_def, &declcode);
59          if (!SaveType(struct_def, declcode, true)) return false;
60        }
61        return true;
62      }
63
64      // Begin by declaring namespace and imports.
65      void BeginFile(const std::string name_space_name,
66                     const bool needs_imports, std::string *code_ptr) {
67        std::string &code = *code_ptr;
68        code += "<?php\n";
69        code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
70
71        if (!name_space_name.empty()) {
72          code += "namespace " + name_space_name + ";\n\n";
73        }
74
75        if (needs_imports) {
76          code += "use \\Google\\FlatBuffers\\Struct;\n";
77          code += "use \\Google\\FlatBuffers\\Table;\n";
78          code += "use \\Google\\FlatBuffers\\ByteBuffer;\n";
79          code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n";
80          code += "\n";
81        }
82      }
83
84      // Save out the generated code for a Php Table type.
85      bool SaveType(const Definition &def, const std::string &classcode,
86                    bool needs_imports) {
87        if (!classcode.length()) return true;
88
89        std::string code = "";
90        BeginFile(FullNamespace("\\", *def.defined_namespace),
91                  needs_imports, &code);
92        code += classcode;
93
94        std::string filename = NamespaceDir(*def.defined_namespace) +
95                               def.name + ".php";
96        return SaveFile(filename.c_str(), code, false);
97      }
98
99    // Begin a class declaration.
100    static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
101      std::string &code = *code_ptr;
102      if (struct_def.fixed) {
103        code += "class " + struct_def.name + " extends Struct\n";
104      } else {
105        code += "class " + struct_def.name + " extends Table\n";
106      }
107      code += "{\n";
108    }
109
110    static void EndClass(std::string *code_ptr) {
111      std::string &code = *code_ptr;
112      code += "}\n";
113    }
114
115    // Begin enum code with a class declaration.
116    static void BeginEnum(const std::string class_name, std::string *code_ptr) {
117      std::string &code = *code_ptr;
118      code += "class " + class_name + "\n{\n";
119    }
120
121    // A single enum member.
122    static void EnumMember(const EnumVal ev, std::string *code_ptr) {
123      std::string &code = *code_ptr;
124      code += Indent + "const ";
125      code += ev.name;
126      code += " = ";
127      code += NumToString(ev.value) + ";\n";
128    }
129
130    // End enum code.
131    static void EndEnum(std::string *code_ptr) {
132      std::string &code = *code_ptr;
133      code += "}\n";
134    }
135
136    // Initialize a new struct or table from existing data.
137    static void NewRootTypeFromBuffer(const StructDef &struct_def,
138      std::string *code_ptr) {
139      std::string &code = *code_ptr;
140
141      code += Indent + "/**\n";
142      code += Indent + " * @param ByteBuffer $bb\n";
143      code += Indent + " * @return " + struct_def.name + "\n";
144      code += Indent + " */\n";
145      code += Indent + "public static function getRootAs";
146      code += struct_def.name;
147      code += "(ByteBuffer $bb)\n";
148      code += Indent + "{\n";
149
150      code += Indent + Indent + "$obj = new " + struct_def.name + "();\n";
151      code += Indent + Indent;
152      code += "return ($obj->init($bb->getInt($bb->getPosition())";
153      code += " + $bb->getPosition(), $bb));\n";
154      code += Indent + "}\n\n";
155    }
156
157    // Initialize an existing object with other data, to avoid an allocation.
158    static void InitializeExisting(const StructDef &struct_def,
159      std::string *code_ptr) {
160      std::string &code = *code_ptr;
161
162      code += Indent + "/**\n";
163      code += Indent + " * @param int $_i offset\n";
164      code += Indent + " * @param ByteBuffer $_bb\n";
165      code += Indent + " * @return " + struct_def.name + "\n";
166      code += Indent + " **/\n";
167      code += Indent + "public function init($_i, ByteBuffer $_bb)\n";
168      code += Indent + "{\n";
169      code += Indent + Indent + "$this->bb_pos = $_i;\n";
170      code += Indent + Indent + "$this->bb = $_bb;\n";
171      code += Indent + Indent + "return $this;\n";
172      code += Indent + "}\n\n";
173    }
174
175    // Get the length of a vector.
176    static void GetVectorLen(const FieldDef &field,
177      std::string *code_ptr) {
178      std::string &code = *code_ptr;
179
180      code += Indent + "/**\n";
181      code += Indent + " * @return int\n";
182      code += Indent + " */\n";
183      code += Indent + "public function get";
184      code += MakeCamel(field.name) + "Length()\n";
185      code += Indent + "{\n";
186      code += Indent + Indent + "$o = $this->__offset(";
187      code += NumToString(field.value.offset) + ");\n";
188      code += Indent + Indent;
189      code += "return $o != 0 ? $this->__vector_len($o) : 0;\n";
190      code += Indent + "}\n\n";
191    }
192
193    // Get a [ubyte] vector as a byte array.
194    static void GetUByte(const FieldDef &field,
195      std::string *code_ptr) {
196      std::string &code = *code_ptr;
197
198      code += Indent + "/**\n";
199      code += Indent + " * @return string\n";
200      code += Indent + " */\n";
201      code += Indent + "public function get";
202      code += MakeCamel(field.name) + "Bytes()\n";
203      code += Indent + "{\n";
204      code += Indent + Indent + "return $this->__vector_as_bytes(";
205      code += NumToString(field.value.offset) + ");\n";
206      code += Indent + "}\n\n";
207    }
208
209    // Get the value of a struct's scalar.
210    static void GetScalarFieldOfStruct(const FieldDef &field,
211      std::string *code_ptr) {
212      std::string &code = *code_ptr;
213      std::string getter = GenGetter(field.value.type);
214
215      code += Indent + "/**\n";
216      code += Indent + " * @return ";
217      code += GenTypeGet(field.value.type) + "\n";
218      code += Indent + " */\n";
219      code += Indent + "public function " + getter;
220      code += MakeCamel(field.name) + "()\n";
221      code += Indent + "{\n";
222      code += Indent + Indent + "return ";
223
224      code += "$this->bb->get";
225      code += MakeCamel(GenTypeGet(field.value.type));
226      code += "($this->bb_pos + ";
227      code += NumToString(field.value.offset) + ")";
228      code += ";\n";
229
230      code += Indent + "}\n\n";
231    }
232
233    // Get the value of a table's scalar.
234    void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) {
235      std::string &code = *code_ptr;
236      std::string getter = GenGetter(field.value.type);
237
238      code += Indent + "/**\n";
239      code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
240      code += Indent + " */\n";
241      code += Indent + "public function get";
242      code += MakeCamel(field.name);
243      code += "()\n";
244      code += Indent + "{\n";
245      code += Indent + Indent +
246        "$o = $this->__offset(" +
247        NumToString(field.value.offset) +
248        ");\n" + Indent + Indent + "return $o != 0 ? ";
249      code += "$this->bb->get";
250      code += MakeCamel(GenTypeGet(field.value.type)) + "($o + $this->bb_pos)";
251      code += " : " + GenDefaultValue(field.value) + ";\n";
252      code += Indent + "}\n\n";
253    }
254
255    // Get a struct by initializing an existing struct.
256    // Specific to Struct.
257    void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) {
258      std::string &code = *code_ptr;
259
260      code += Indent + "/**\n";
261      code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
262      code += Indent + " */\n";
263      code += Indent + "public function get";
264      code += MakeCamel(field.name) + "()\n";
265      code += Indent + "{\n";
266      code += Indent + Indent + "$obj = new ";
267      code += GenTypeGet(field.value.type) + "();\n";
268      code += Indent + Indent + "$obj->init($this->bb_pos + ";
269      code += NumToString(field.value.offset) + ", $this->bb);";
270      code += "\n" + Indent + Indent + "return $obj;\n";
271      code += Indent + "}\n\n";
272    }
273
274    // Get a struct by initializing an existing struct.
275    // Specific to Table.
276    void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) {
277      std::string &code = *code_ptr;
278
279      code += Indent + "public function get";
280      code += MakeCamel(field.name);
281      code += "()\n";
282      code += Indent + "{\n";
283      code += Indent + Indent + "$obj = new ";
284      code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
285      code += Indent + Indent +
286        "$o = $this->__offset(" +
287        NumToString(field.value.offset) +
288        ");\n";
289      code += Indent + Indent;
290      code += "return $o != 0 ? $obj->init(";
291      if (field.value.type.struct_def->fixed)
292      {
293        code += "$o + $this->bb_pos, $this->bb) : ";
294      } else {
295        code += "$this->__indirect($o + $this->bb_pos), $this->bb) : ";
296      }
297      code += GenDefaultValue(field.value) + ";\n";
298      code += Indent + "}\n\n";
299    }
300
301    // Get the value of a string.
302    void GetStringField(const FieldDef &field, std::string *code_ptr) {
303      std::string &code = *code_ptr;
304      code += Indent + "public function get";
305      code += MakeCamel(field.name);
306      code += "()\n";
307      code += Indent + "{\n";
308      code += Indent + Indent +
309        "$o = $this->__offset(" +
310        NumToString(field.value.offset) +
311        ");\n";
312      code += Indent + Indent;
313      code += "return $o != 0 ? $this->__string($o + $this->bb_pos) : ";
314      code += GenDefaultValue(field.value) + ";\n";
315      code += Indent + "}\n\n";
316    }
317
318    // Get the value of a union from an object.
319    void GetUnionField(const FieldDef &field, std::string *code_ptr) {
320      std::string &code = *code_ptr;
321
322      code += Indent + "/**\n";
323      code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
324      code += Indent + " */\n";
325      code += Indent + "public function get";
326      code += MakeCamel(field.name) + "($obj)\n";
327      code += Indent + "{\n";
328      code += Indent + Indent +
329        "$o = $this->__offset(" +
330        NumToString(field.value.offset) +
331        ");\n";
332      code += Indent + Indent;
333      code += "return $o != 0 ? $this->__union($obj, $o) : null;\n";
334      code += Indent + "}\n\n";
335    }
336
337    // Get the value of a vector's struct member.
338    void GetMemberOfVectorOfStruct(const StructDef &struct_def,
339      const FieldDef &field, std::string *code_ptr) {
340      std::string &code = *code_ptr;
341      auto vectortype = field.value.type.VectorType();
342
343      code += Indent + "/**\n";
344      code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
345      code += Indent + " */\n";
346      code += Indent + "public function get";
347      code += MakeCamel(field.name);
348      code += "($j)\n";
349      code += Indent + "{\n";
350      code += Indent + Indent +
351        "$o = $this->__offset(" +
352        NumToString(field.value.offset) +
353        ");\n";
354      code += Indent + Indent + "$obj = new ";
355      code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
356
357      switch (field.value.type.base_type) {
358      case BASE_TYPE_STRUCT:
359        if (struct_def.fixed) {
360          code += Indent + Indent;
361          code += "return $o != 0 ? $obj->init($this->bb_pos +"
362            + NumToString(field.value.offset) + ", $this->bb) : null;\n";
363        } else {
364          code += Indent + Indent + "return $o != 0 ? $obj->init(";
365          code += field.value.type.struct_def->fixed
366            ? "$o + $this->bb_pos"
367            : "$this->__indirect($o + $this->bb_pos)";
368          code += ", $this->bb) : null;\n";
369        }
370        break;
371      case BASE_TYPE_STRING:
372        code += "// base_type_string\n";
373        // TODO(chobie): do we need this?
374        break;
375      case BASE_TYPE_VECTOR:
376        if (vectortype.base_type == BASE_TYPE_STRUCT) {
377          code += Indent + Indent + "return $o != 0 ? $obj->init(";
378          if (vectortype.struct_def->fixed) {
379            code += "$this->__vector($o) + $j *";
380            code += NumToString(InlineSize(vectortype));
381          } else {
382            code += "$this->__indirect($this->__vector($o) + $j * ";
383            code += NumToString(InlineSize(vectortype)) + ")";
384          }
385          code += ", $this->bb) : null;\n";
386        }
387        break;
388      case BASE_TYPE_UNION:
389        code += Indent + Indent + "return $o != 0 ? $this->";
390        code += GenGetter(field.value.type) + "($obj, $o); null;\n";
391        break;
392      default:
393        break;
394      }
395
396      code += Indent + "}\n\n";
397    }
398
399    // Get the value of a vector's non-struct member. Uses a named return
400    // argument to conveniently set the zero value for the result.
401    void GetMemberOfVectorOfNonStruct(const FieldDef &field,
402      std::string *code_ptr) {
403      std::string &code = *code_ptr;
404      auto vectortype = field.value.type.VectorType();
405
406      code += Indent + "/**\n";
407      code += Indent + " * @param int offset\n";
408      code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
409      code += Indent + " */\n";
410      code += Indent + "public function get";
411      code += MakeCamel(field.name);
412      code += "($j)\n";
413      code += Indent + "{\n";
414      code += Indent + Indent +
415        "$o = $this->__offset(" +
416        NumToString(field.value.offset) +
417        ");\n";
418
419      if (field.value.type.VectorType().base_type == BASE_TYPE_STRING) {
420        code += Indent + Indent;
421        code += "return $o != 0 ? $this->__string($this->__vector($o) + $j * ";
422        code += NumToString(InlineSize(vectortype)) + ") : ";
423        code += GenDefaultValue(field.value) + ";\n";
424      } else {
425        code += Indent + Indent + "return $o != 0 ? $this->bb->get";
426        code += MakeCamel(GenTypeGet(field.value.type));
427        code += "($this->__vector($o) + $j * ";
428        code += NumToString(InlineSize(vectortype)) + ") : ";
429        code += GenDefaultValue(field.value) + ";\n";
430      }
431      code += Indent + "}\n\n";
432    }
433
434    // Get the value of a vector's union member. Uses a named return
435    // argument to conveniently set the zero value for the result.
436    void GetMemberOfVectorOfUnion(const FieldDef &field,
437      std::string *code_ptr) {
438      std::string &code = *code_ptr;
439      auto vectortype = field.value.type.VectorType();
440
441      code += Indent + "/**\n";
442      code += Indent + " * @param int offset\n";
443      code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
444      code += Indent + " */\n";
445      code += Indent + "public function get";
446      code += MakeCamel(field.name);
447      code += "($j, $obj)\n";
448      code += Indent + "{\n";
449      code += Indent + Indent +
450        "$o = $this->__offset(" +
451        NumToString(field.value.offset) +
452        ");\n";
453      code += Indent + Indent + "return $o != 0 ? ";
454      code += "$this->__union($obj, $this->__vector($o) + $j * ";
455      code += NumToString(InlineSize(vectortype)) + " - $this->bb_pos) : null;\n";
456      code += Indent + "}\n\n";
457    }
458
459    // Recursively generate arguments for a constructor, to deal with nested
460    // structs.
461    static void StructBuilderArgs(const StructDef &struct_def,
462      const char *nameprefix,
463      std::string *code_ptr) {
464      for (auto it = struct_def.fields.vec.begin();
465      it != struct_def.fields.vec.end();
466        ++it) {
467        auto &field = **it;
468        if (IsStruct(field.value.type)) {
469          // Generate arguments for a struct inside a struct. To ensure names
470          // don't clash, and to make it obvious
471          // these arguments are constructing
472          // a nested struct, prefix the name with the field name.
473          StructBuilderArgs(*field.value.type.struct_def,
474            (nameprefix + (field.name + "_")).c_str(),
475            code_ptr);
476        } else {
477          std::string &code = *code_ptr;
478          code += (std::string)", $" + nameprefix;
479          code += MakeCamel(field.name, false);
480        }
481      }
482    }
483
484    // Recursively generate struct construction statements and instert manual
485    // padding.
486    static void StructBuilderBody(const StructDef &struct_def,
487      const char *nameprefix,
488      std::string *code_ptr) {
489      std::string &code = *code_ptr;
490      code += Indent + Indent + "$builder->prep(";
491      code += NumToString(struct_def.minalign) + ", ";
492      code += NumToString(struct_def.bytesize) + ");\n";
493      for (auto it = struct_def.fields.vec.rbegin();
494      it != struct_def.fields.vec.rend();
495        ++it) {
496        auto &field = **it;
497        if (field.padding) {
498          code += Indent + Indent + "$builder->pad(";
499          code += NumToString(field.padding) + ");\n";
500        }
501        if (IsStruct(field.value.type)) {
502          StructBuilderBody(*field.value.type.struct_def,
503            (nameprefix + (field.name + "_")).c_str(),
504            code_ptr);
505        } else {
506          code += Indent + Indent + "$builder->put" + GenMethod(field) + "($";
507          code += nameprefix + MakeCamel(field.name, false) + ");\n";
508        }
509      }
510    }
511
512    // Get the value of a table's starting offset.
513    static void GetStartOfTable(const StructDef &struct_def,
514      std::string *code_ptr) {
515      std::string &code = *code_ptr;
516
517      code += Indent + "/**\n";
518      code += Indent + " * @param FlatBufferBuilder $builder\n";
519      code += Indent + " * @return void\n";
520      code += Indent + " */\n";
521      code += Indent + "public static function start" + struct_def.name;
522      code += "(FlatBufferBuilder $builder)\n";
523      code += Indent + "{\n";
524      code += Indent + Indent + "$builder->StartObject(";
525      code += NumToString(struct_def.fields.vec.size());
526      code += ");\n";
527      code += Indent + "}\n\n";
528
529      code += Indent + "/**\n";
530      code += Indent + " * @param FlatBufferBuilder $builder\n";
531      code += Indent + " * @return " + struct_def.name + "\n";
532      code += Indent + " */\n";
533      code += Indent + "public static function create" + struct_def.name;
534      code += "(FlatBufferBuilder $builder, ";
535
536      for (auto it = struct_def.fields.vec.begin();
537      it != struct_def.fields.vec.end();
538        ++it) {
539        auto &field = **it;
540
541        if (field.deprecated) continue;
542        code += "$" + field.name;
543        if (!(it == (--struct_def.fields.vec.end()))) {
544          code += ", ";
545        }
546      }
547      code += ")\n";
548      code += Indent + "{\n";
549      code += Indent + Indent + "$builder->startObject(";
550      code += NumToString(struct_def.fields.vec.size());
551      code += ");\n";
552      for (auto it = struct_def.fields.vec.begin();
553      it != struct_def.fields.vec.end();
554        ++it) {
555        auto &field = **it;
556        if (field.deprecated) continue;
557
558        code += Indent + Indent + "self::add";
559        code += MakeCamel(field.name) + "($builder, $" + field.name + ");\n";
560      }
561
562      code += Indent + Indent + "$o = $builder->endObject();\n";
563
564      for (auto it = struct_def.fields.vec.begin();
565      it != struct_def.fields.vec.end();
566        ++it) {
567        auto &field = **it;
568        if (!field.deprecated && field.required) {
569          code += Indent + Indent + "$builder->required($o, ";
570          code += NumToString(field.value.offset);
571          code += ");  // " + field.name + "\n";
572        }
573      }
574      code += Indent + Indent + "return $o;\n";
575      code += Indent + "}\n\n";
576    }
577
578    // Set the value of a table's field.
579    static void BuildFieldOfTable(const FieldDef &field,
580      const size_t offset,
581      std::string *code_ptr) {
582      std::string &code = *code_ptr;
583
584
585      code += Indent + "/**\n";
586      code += Indent + " * @param FlatBufferBuilder $builder\n";
587      code += Indent + " * @param " + GenTypeBasic(field.value.type) + "\n";
588      code += Indent + " * @return void\n";
589      code += Indent + " */\n";
590      code += Indent + "public static function ";
591      code += "add" + MakeCamel(field.name);
592      code += "(FlatBufferBuilder $builder, ";
593      code += "$" + MakeCamel(field.name, false);
594      code += ")\n";
595      code += Indent + "{\n";
596      code += Indent + Indent + "$builder->add";
597      code += GenMethod(field) + "X(";
598      code += NumToString(offset) + ", ";
599
600
601      code += "$" + MakeCamel(field.name, false);
602      code += ", ";
603
604      if (field.value.type.base_type == BASE_TYPE_BOOL) {
605        code += "false";
606      } else {
607        code += field.value.constant;
608      }
609      code += ");\n";
610      code += Indent + "}\n\n";
611    }
612
613    // Set the value of one of the members of a table's vector.
614    static void BuildVectorOfTable(const FieldDef &field,
615      std::string *code_ptr) {
616      std::string &code = *code_ptr;
617
618      auto vector_type = field.value.type.VectorType();
619      auto alignment = InlineAlignment(vector_type);
620      auto elem_size = InlineSize(vector_type);
621      code += Indent + "/**\n";
622      code += Indent + " * @param FlatBufferBuilder $builder\n";
623      code += Indent + " * @param array offset array\n";
624      code += Indent + " * @return int vector offset\n";
625      code += Indent + " */\n";
626      code += Indent + "public static function create";
627      code += MakeCamel(field.name);
628      code += "Vector(FlatBufferBuilder $builder, array $data)\n";
629      code += Indent + "{\n";
630      code += Indent + Indent + "$builder->startVector(";
631      code += NumToString(elem_size);
632      code += ", count($data), " + NumToString(alignment);
633      code += ");\n";
634      code += Indent + Indent;
635      code += "for ($i = count($data) - 1; $i >= 0; $i--) {\n";
636      if (IsScalar(field.value.type.VectorType().base_type)) {
637        code += Indent + Indent + Indent;
638        code += "$builder->add";
639        code += MakeCamel(GenTypeBasic(field.value.type.VectorType()));
640        code += "($data[$i]);\n";
641      } else {
642        code += Indent + Indent + Indent;
643        code += "$builder->addOffset($data[$i]);\n";
644      }
645      code += Indent + Indent + "}\n";
646      code += Indent + Indent + "return $builder->endVector();\n";
647      code += Indent + "}\n\n";
648
649
650      code += Indent + "/**\n";
651      code += Indent + " * @param FlatBufferBuilder $builder\n";
652      code += Indent + " * @param int $numElems\n";
653      code += Indent + " * @return void\n";
654      code += Indent + " */\n";
655      code += Indent + "public static function start";
656      code += MakeCamel(field.name);
657      code += "Vector(FlatBufferBuilder $builder, $numElems)\n";
658      code += Indent + "{\n";
659      code += Indent + Indent +  "$builder->startVector(";
660      code += NumToString(elem_size);
661      code += ", $numElems, " + NumToString(alignment);
662      code += ");\n";
663      code += Indent + "}\n\n";
664    }
665
666    // Get the offset of the end of a table.
667    void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
668      std::string &code = *code_ptr;
669
670
671      code += Indent + "/**\n";
672      code += Indent + " * @param FlatBufferBuilder $builder\n";
673      code += Indent + " * @return int table offset\n";
674      code += Indent + " */\n";
675      code += Indent + "public static function end" + struct_def.name;
676      code += "(FlatBufferBuilder $builder)\n";
677      code += Indent + "{\n";
678      code += Indent + Indent + "$o = $builder->endObject();\n";
679
680
681      for (auto it = struct_def.fields.vec.begin();
682      it != struct_def.fields.vec.end();
683        ++it) {
684        auto &field = **it;
685        if (!field.deprecated && field.required) {
686          code += Indent + Indent + "$builder->required($o, ";
687          code += NumToString(field.value.offset);
688          code += ");  // " + field.name + "\n";
689        }
690      }
691      code += Indent + Indent + "return $o;\n";
692      code += Indent + "}\n";
693
694      if (parser_.root_struct_def_ == &struct_def) {
695        code += "\n";
696        code += Indent + "public static function finish";
697        code += struct_def.name;
698        code += "Buffer(FlatBufferBuilder $builder, $offset)\n";
699        code += Indent + "{\n";
700        code += Indent + Indent + "$builder->finish($offset";
701
702        if (parser_.file_identifier_.length())
703          code += ", \"" + parser_.file_identifier_ + "\"";
704        code += ");\n";
705        code += Indent + "}\n";
706      }
707    }
708
709  // Generate a struct field, conditioned on its child type(s).
710    void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
711      std::string *code_ptr) {
712      GenComment(field.doc_comment, code_ptr, nullptr);
713
714      if (IsScalar(field.value.type.base_type)) {
715        if (struct_def.fixed) {
716          GetScalarFieldOfStruct(field, code_ptr);
717        } else {
718          GetScalarFieldOfTable(field, code_ptr);
719        }
720      } else {
721        switch (field.value.type.base_type) {
722        case BASE_TYPE_STRUCT:
723          if (struct_def.fixed) {
724            GetStructFieldOfStruct(field, code_ptr);
725          } else {
726            GetStructFieldOfTable(field, code_ptr);
727          }
728          break;
729        case BASE_TYPE_STRING:
730          GetStringField(field, code_ptr);
731          break;
732        case BASE_TYPE_VECTOR: {
733          auto vectortype = field.value.type.VectorType();
734          if (vectortype.base_type == BASE_TYPE_UNION) {
735            GetMemberOfVectorOfUnion(field, code_ptr);
736          } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
737            GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
738          } else {
739            GetMemberOfVectorOfNonStruct(field, code_ptr);
740          }
741          break;
742        }
743        case BASE_TYPE_UNION:
744          GetUnionField(field, code_ptr);
745          break;
746        default:
747          assert(0);
748        }
749      }
750      if (field.value.type.base_type == BASE_TYPE_VECTOR) {
751        GetVectorLen(field, code_ptr);
752        if (field.value.type.element == BASE_TYPE_UCHAR) {
753          GetUByte(field, code_ptr);
754        }
755      }
756    }
757
758    // Generate table constructors, conditioned on its members' types.
759    void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
760      GetStartOfTable(struct_def, code_ptr);
761
762      for (auto it = struct_def.fields.vec.begin();
763      it != struct_def.fields.vec.end();
764        ++it) {
765        auto &field = **it;
766        if (field.deprecated) continue;
767
768        auto offset = it - struct_def.fields.vec.begin();
769        if (field.value.type.base_type == BASE_TYPE_UNION) {
770          std::string &code = *code_ptr;
771          code += Indent + "public static function add";
772          code += MakeCamel(field.name);
773          code += "(FlatBufferBuilder $builder, $offset)\n";
774          code += Indent + "{\n";
775          code += Indent + Indent + "$builder->addOffsetX(";
776          code += NumToString(offset) + ", $offset, 0);\n";
777          code += Indent + "}\n\n";
778        } else {
779          BuildFieldOfTable(field, offset, code_ptr);
780        }
781        if (field.value.type.base_type == BASE_TYPE_VECTOR) {
782          BuildVectorOfTable(field, code_ptr);
783        }
784      }
785
786      GetEndOffsetOnTable(struct_def, code_ptr);
787    }
788
789    // Generate struct or table methods.
790    void GenStruct(const StructDef &struct_def,
791      std::string *code_ptr) {
792      if (struct_def.generated) return;
793
794      GenComment(struct_def.doc_comment, code_ptr, nullptr);
795      BeginClass(struct_def, code_ptr);
796
797      if (!struct_def.fixed) {
798        // Generate a special accessor for the table that has been declared as
799        // the root type.
800        NewRootTypeFromBuffer(struct_def, code_ptr);
801      }
802
803      std::string &code = *code_ptr;
804      if (!struct_def.fixed) {
805        if (parser_.file_identifier_.length()) {
806          // Return the identifier
807          code += Indent + "public static function " + struct_def.name;
808          code += "Identifier()\n";
809          code += Indent + "{\n";
810          code += Indent + Indent + "return \"";
811          code += parser_.file_identifier_ + "\";\n";
812          code += Indent + "}\n\n";
813
814          // Check if a buffer has the identifier.
815          code += Indent + "public static function " + struct_def.name;
816          code += "BufferHasIdentifier(ByteBuffer $buf)\n";
817          code += Indent + "{\n";
818          code += Indent + Indent + "return self::";
819          code += "__has_identifier($buf, self::";
820          code += struct_def.name + "Identifier());\n";
821          code += Indent + "}\n\n";
822        }
823
824        if (parser_.file_extension_.length()) {
825          // Return the extension
826          code += Indent + "public static function " + struct_def.name;
827          code += "Extension()\n";
828          code += Indent + "{\n";
829          code += Indent + Indent + "return \"" + parser_.file_extension_;
830          code += "\";\n";
831          code += Indent + "}\n\n";
832        }
833      }
834
835      // Generate the Init method that sets the field in a pre-existing
836      // accessor object. This is to allow object reuse.
837      InitializeExisting(struct_def, code_ptr);
838      for (auto it = struct_def.fields.vec.begin();
839      it != struct_def.fields.vec.end();
840        ++it) {
841        auto &field = **it;
842        if (field.deprecated) continue;
843
844        GenStructAccessor(struct_def, field, code_ptr);
845      }
846
847      if (struct_def.fixed) {
848        // create a struct constructor function
849        GenStructBuilder(struct_def, code_ptr);
850      } else {
851        // Create a set of functions that allow table construction.
852        GenTableBuilders(struct_def, code_ptr);
853      }
854      EndClass(code_ptr);
855    }
856
857    // Generate enum declarations.
858    static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
859      if (enum_def.generated) return;
860
861      GenComment(enum_def.doc_comment, code_ptr, nullptr);
862      BeginEnum(enum_def.name, code_ptr);
863      for (auto it = enum_def.vals.vec.begin();
864      it != enum_def.vals.vec.end();
865        ++it) {
866        auto &ev = **it;
867        GenComment(ev.doc_comment, code_ptr, nullptr);
868        EnumMember(ev, code_ptr);
869      }
870
871      std::string &code = *code_ptr;
872      code += "\n";
873      code += Indent + "private static $names = array(\n";
874      for (auto it = enum_def.vals.vec.begin();
875        it != enum_def.vals.vec.end(); ++it) {
876        auto &ev = **it;
877        code += Indent + Indent + "\"" + ev.name + "\",\n";
878      }
879
880      code += Indent + ");\n\n";
881      code += Indent + "public static function Name($e)\n";
882      code += Indent + "{\n";
883      code += Indent + Indent + "if (!isset(self::$names[$e])) {\n";
884      code += Indent + Indent + Indent + "throw new \\Exception();\n";
885      code += Indent + Indent + "}\n";
886      code += Indent + Indent + "return self::$names[$e];\n";
887      code += Indent + "}\n";
888      EndEnum(code_ptr);
889    }
890
891    // Returns the function name that is able to read a value of the given type.
892    static std::string GenGetter(const Type &type) {
893      switch (type.base_type) {
894      case BASE_TYPE_STRING: return "__string";
895      case BASE_TYPE_STRUCT: return "__struct";
896      case BASE_TYPE_UNION: return "__union";
897      case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
898      default:
899        return "Get";
900      }
901    }
902
903    // Returns the method name for use with add/put calls.
904    static std::string GenMethod(const FieldDef &field) {
905      return IsScalar(field.value.type.base_type)
906        ? MakeCamel(GenTypeBasic(field.value.type))
907        : (IsStruct(field.value.type) ? "Struct" : "Offset");
908    }
909
910    static std::string GenTypeBasic(const Type &type) {
911      static const char *ctypename[] = {
912#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
913    CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
914    #NTYPE,
915        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
916#undef FLATBUFFERS_TD
917      };
918      return ctypename[type.base_type];
919    }
920
921    std::string GenDefaultValue(const Value &value) {
922      if (value.type.enum_def) {
923        if (auto val = value.type.enum_def->ReverseLookup(
924          atoi(value.constant.c_str()), false)) {
925          return WrapInNameSpace(*value.type.enum_def) + "::" + val->name;
926        }
927      }
928
929      switch (value.type.base_type) {
930      case BASE_TYPE_BOOL:
931        return value.constant == "0" ? "false" : "true";
932
933      case BASE_TYPE_STRING:
934        return "null";
935
936      case BASE_TYPE_LONG:
937      case BASE_TYPE_ULONG:
938        if (value.constant != "0") {
939          int64_t constant = StringToInt(value.constant.c_str());
940          return NumToString(constant);
941        }
942        return "0";
943
944      default:
945        return value.constant;
946      }
947    }
948
949    static std::string GenTypePointer(const Type &type) {
950      switch (type.base_type) {
951      case BASE_TYPE_STRING:
952        return "string";
953      case BASE_TYPE_VECTOR:
954        return GenTypeGet(type.VectorType());
955      case BASE_TYPE_STRUCT:
956        return type.struct_def->name;
957      case BASE_TYPE_UNION:
958        // fall through
959      default:
960        return "Table";
961      }
962    }
963
964    static std::string GenTypeGet(const Type &type) {
965      return IsScalar(type.base_type)
966        ? GenTypeBasic(type)
967        : GenTypePointer(type);
968    }
969
970    // Create a struct with a builder and the struct's arguments.
971    static void GenStructBuilder(const StructDef &struct_def,
972      std::string *code_ptr) {
973      std::string &code = *code_ptr;
974      code += "\n";
975      code += Indent + "/**\n";
976      code += Indent + " * @return int offset\n";
977      code += Indent + " */\n";
978      code += Indent + "public static function create" + struct_def.name;
979      code += "(FlatBufferBuilder $builder";
980      StructBuilderArgs(struct_def, "", code_ptr);
981      code += ")\n";
982      code += Indent + "{\n";
983
984      StructBuilderBody(struct_def, "", code_ptr);
985
986      code += Indent + Indent + "return $builder->offset();\n";
987      code += Indent + "}\n";
988    }
989
990    };
991    }  // namespace php
992
993    bool GeneratePhp(const Parser &parser, const std::string &path,
994                     const std::string &file_name) {
995      php::PhpGenerator generator(parser, path, file_name);
996      return generator.generate();
997    }
998    }  // namespace flatbuffers
999